LCOV - code coverage report
Current view: top level - src/utils/common - MsgHandler.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 160 190 84.2 %
Date: 2024-05-02 15:31:40 Functions: 21 26 80.8 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
       4             : // This program and the accompanying materials are made available under the
       5             : // terms of the Eclipse Public License 2.0 which is available at
       6             : // https://www.eclipse.org/legal/epl-2.0/
       7             : // This Source Code may also be made available under the following Secondary
       8             : // Licenses when the conditions for such availability set forth in the Eclipse
       9             : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10             : // or later which is available at
      11             : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12             : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13             : /****************************************************************************/
      14             : /// @file    MsgHandler.cpp
      15             : /// @author  Daniel Krajzewicz
      16             : /// @author  Michael Behrisch
      17             : /// @author  Mirko Barthauer
      18             : /// @date    Tue, 17 Jun 2003
      19             : ///
      20             : // Retrieves messages about the process and gives them further to output
      21             : /****************************************************************************/
      22             : #include <config.h>
      23             : 
      24             : #include <string>
      25             : #include <cassert>
      26             : #include <vector>
      27             : #include <algorithm>
      28             : #include <iostream>
      29             : #include <chrono>
      30             : #ifdef WIN32
      31             : #define NOMINMAX
      32             : #include <windows.h>
      33             : #undef NOMINMAX
      34             : #else
      35             : #include <unistd.h>
      36             : #endif
      37             : #include <utils/options/OptionsCont.h>
      38             : #include <utils/iodevices/OutputDevice.h>
      39             : #include <utils/common/UtilExceptions.h>
      40             : #include "MsgHandler.h"
      41             : 
      42             : 
      43             : // ===========================================================================
      44             : // static member variables
      45             : // ===========================================================================
      46             : MsgHandler::Factory MsgHandler::myFactory = nullptr;
      47             : MsgHandler* MsgHandler::myDebugInstance = nullptr;
      48             : MsgHandler* MsgHandler::myGLDebugInstance = nullptr;
      49             : MsgHandler* MsgHandler::myErrorInstance = nullptr;
      50             : MsgHandler* MsgHandler::myWarningInstance = nullptr;
      51             : MsgHandler* MsgHandler::myMessageInstance = nullptr;
      52             : bool MsgHandler::myAmProcessingProcess = false;
      53             : bool MsgHandler::myWriteDebugMessages = false;
      54             : bool MsgHandler::myWriteDebugGLMessages = false;
      55             : bool MsgHandler::myWriteTimestamps = false;
      56             : bool MsgHandler::myWriteProcessId = false;
      57             : std::string MsgHandler::myErrorPrefix = "Error: ";
      58             : std::string MsgHandler::myWarningPrefix = "Warning: ";
      59             : 
      60             : 
      61             : // ===========================================================================
      62             : // method definitions
      63             : // ===========================================================================
      64             : 
      65             : MsgHandler*
      66     1232997 : MsgHandler::getMessageInstance() {
      67     1232997 :     if (myMessageInstance == nullptr) {
      68       71989 :         if (myFactory == nullptr) {
      69       32346 :             myMessageInstance = new MsgHandler(MsgType::MT_MESSAGE);
      70             :         } else {
      71       39643 :             myMessageInstance = myFactory(MsgType::MT_MESSAGE);
      72             :         }
      73             :     }
      74     1232997 :     return myMessageInstance;
      75             : }
      76             : 
      77             : 
      78             : MsgHandler*
      79      779997 : MsgHandler::getWarningInstance() {
      80      779997 :     if (myWarningInstance == nullptr) {
      81      110379 :         if (myFactory == nullptr) {
      82       59893 :             myWarningInstance = new MsgHandler(MsgType::MT_WARNING);
      83             :         } else {
      84       50486 :             myWarningInstance = myFactory(MsgType::MT_WARNING);
      85             :         }
      86             :     }
      87      779997 :     return myWarningInstance;
      88             : }
      89             : 
      90             : 
      91             : MsgHandler*
      92     1467256 : MsgHandler::getErrorInstance() {
      93     1467256 :     if (myErrorInstance == nullptr) {
      94      110366 :         myErrorInstance = new MsgHandler(MsgType::MT_ERROR);
      95             :     }
      96     1467256 :     return myErrorInstance;
      97             : }
      98             : 
      99             : 
     100             : MsgHandler*
     101           0 : MsgHandler::getDebugInstance() {
     102           0 :     if (myDebugInstance == nullptr) {
     103           0 :         myDebugInstance = new MsgHandler(MsgType::MT_DEBUG);
     104             :     }
     105           0 :     return myDebugInstance;
     106             : }
     107             : 
     108             : 
     109             : MsgHandler*
     110           0 : MsgHandler::getGLDebugInstance() {
     111           0 :     if (myGLDebugInstance == nullptr) {
     112           0 :         myGLDebugInstance = new MsgHandler(MsgType::MT_GLDEBUG);
     113             :     }
     114           0 :     return myGLDebugInstance;
     115             : }
     116             : 
     117             : 
     118             : void
     119           0 : MsgHandler::enableDebugMessages(bool enable) {
     120           0 :     myWriteDebugMessages = enable;
     121           0 : }
     122             : 
     123             : void
     124           0 : MsgHandler::enableDebugGLMessages(bool enable) {
     125           0 :     myWriteDebugGLMessages = enable;
     126           0 : }
     127             : 
     128             : 
     129             : std::string
     130           0 : MsgHandler::insertLineBreaks(std::string msg, int lineWidth) {
     131             :     // TODO: check what FXFont::getTextWidth can do
     132             :     //int textWidth = getApp()->getNormalFont()->getTextWidth
     133           0 :     if ((int)msg.size() <= lineWidth) {
     134             :         return msg;
     135             :     }
     136             :     size_t pos = 0;
     137           0 :     size_t nextLineBreak = msg.find('\n');
     138           0 :     size_t spaceAfterLine = msg.find(' ', lineWidth);
     139           0 :     while (spaceAfterLine != std::string::npos) {
     140           0 :         if (nextLineBreak == std::string::npos || nextLineBreak > spaceAfterLine) {
     141             :             msg = msg.replace(spaceAfterLine, 1, "\n");
     142           0 :             pos = spaceAfterLine + 1;
     143             :         } else {
     144           0 :             pos = nextLineBreak + 1;
     145             :         }
     146           0 :         spaceAfterLine = msg.find(' ', pos + lineWidth);
     147           0 :         nextLineBreak = msg.find('\n', pos);
     148             :     }
     149             :     return msg;
     150             : }
     151             : 
     152             : 
     153             : void
     154     1222425 : MsgHandler::inform(std::string msg, bool addType) {
     155     1222425 :     if (addType && !myInitialMessages.empty() && myInitialMessages.size() < 5) {
     156          91 :         myInitialMessages.push_back(msg);
     157             :     }
     158             :     // beautify progress output
     159     1222425 :     if (myAmProcessingProcess) {
     160         744 :         myAmProcessingProcess = false;
     161        1488 :         MsgHandler::getMessageInstance()->inform("");
     162             :     }
     163     2444850 :     msg = build(msg, addType);
     164             :     // inform all receivers
     165     1652484 :     for (auto i : myRetrievers) {
     166      430059 :         i->inform(msg);
     167             :     }
     168             :     // set the information that something occurred
     169     1222425 :     myWasInformed = true;
     170     1222425 : }
     171             : 
     172             : 
     173             : void
     174      116451 : MsgHandler::beginProcessMsg(std::string msg, bool addType) {
     175      232902 :     msg = build(msg, addType);
     176             :     // inform all other receivers
     177      145844 :     for (auto i : myRetrievers) {
     178       29393 :         i->inform(msg, ' ');
     179       29393 :         myAmProcessingProcess = true;
     180             :     }
     181             :     // set the information that something occurred
     182      116451 :     myWasInformed = true;
     183      116451 : }
     184             : 
     185             : 
     186             : void
     187      115049 : MsgHandler::endProcessMsg2(bool success, long duration) {
     188      115049 :     if (success) {
     189      113620 :         if (duration > -1) {
     190      206336 :             endProcessMsg(TLF("done (%ms).", toString(duration)));
     191             :         } else {
     192       20904 :             endProcessMsg(TL("done."));
     193             :         }
     194             :     } else {
     195        2858 :         endProcessMsg(TL("failed."));
     196             :     }
     197      115049 : }
     198             : 
     199             : 
     200             : void
     201      115632 : MsgHandler::endProcessMsg(std::string msg) {
     202             :     // inform all other receivers
     203      144839 :     for (auto i : myRetrievers) {
     204       29207 :         i->inform(msg);
     205             :     }
     206             :     // set the information that something occurred
     207      115632 :     myWasInformed = true;
     208      115632 :     myAmProcessingProcess = false;
     209      115632 : }
     210             : 
     211             : 
     212             : void
     213      325002 : MsgHandler::clear(bool resetInformed) {
     214      325002 :     if (myAggregationThreshold >= 0) {
     215       11477 :         for (const auto& i : myAggregationCount) {
     216        2052 :             if (i.second > myAggregationThreshold) {
     217         892 :                 inform(toString(i.second) + " total messages of type: " + i.first);
     218             :             }
     219             :         }
     220             :     }
     221             :     myAggregationCount.clear();
     222      325002 :     if (!resetInformed && myInitialMessages.size() > 1) {
     223           3 :         const bool wasInformed = myWasInformed;
     224          15 :         for (const std::string& msg : myInitialMessages) {
     225          24 :             inform(msg, false);
     226             :         }
     227             :         myInitialMessages.clear();
     228           3 :         myWasInformed = wasInformed;
     229             :     }
     230      325002 :     if (resetInformed) {
     231      322021 :         myWasInformed = false;
     232             :     }
     233      325002 : }
     234             : 
     235             : 
     236             : void
     237      363909 : MsgHandler::addRetriever(OutputDevice* retriever) {
     238      363909 :     if (!isRetriever(retriever)) {
     239      363909 :         myRetrievers.push_back(retriever);
     240             :     }
     241      363909 : }
     242             : 
     243             : 
     244             : void
     245      829548 : MsgHandler::removeRetriever(OutputDevice* retriever) {
     246      829548 :     std::vector<OutputDevice*>::iterator i = find(myRetrievers.begin(), myRetrievers.end(), retriever);
     247      829548 :     if (i != myRetrievers.end()) {
     248      356588 :         myRetrievers.erase(i);
     249             :     }
     250      829548 : }
     251             : 
     252             : 
     253             : bool
     254      616888 : MsgHandler::isRetriever(OutputDevice* retriever) const {
     255      616888 :     return std::find(myRetrievers.begin(), myRetrievers.end(), retriever) != myRetrievers.end();
     256             : }
     257             : 
     258             : 
     259             : void
     260      226623 : MsgHandler::removeRetrieverFromAllInstances(OutputDevice* out) {
     261      226623 :     if (myDebugInstance != nullptr) {
     262           0 :         myDebugInstance->removeRetriever(out);
     263             :     }
     264      226623 :     if (myGLDebugInstance != nullptr) {
     265           0 :         myGLDebugInstance->removeRetriever(out);
     266             :     }
     267      226623 :     if (myErrorInstance != nullptr) {
     268      226623 :         myErrorInstance->removeRetriever(out);
     269             :     }
     270      226623 :     if (myWarningInstance != nullptr) {
     271      226623 :         myWarningInstance->removeRetriever(out);
     272             :     }
     273      226623 :     if (myMessageInstance != nullptr) {
     274      188220 :         myMessageInstance->removeRetriever(out);
     275             :     }
     276      226623 : }
     277             : 
     278             : 
     279             : void
     280       48368 : MsgHandler::setupI18n(const std::string& locale) {
     281             : #ifdef HAVE_INTL
     282       48368 :     if (locale != "") {
     283             : #ifdef WIN32
     284             :         _putenv_s("LANGUAGE", locale.data());
     285             : #else
     286       48368 :         setenv("LANGUAGE", locale.data(), true);
     287             : #endif
     288             :     }
     289       48368 :     if (!setlocale(LC_MESSAGES, "")) {
     290           0 :         WRITE_WARNINGF(TL("Could not set locale to '%'."), locale);
     291             :     }
     292       48368 :     const char* sumoPath = getenv("SUMO_HOME");
     293       48368 :     if (sumoPath == nullptr) {
     294          32 :         if (!bindtextdomain("sumo", nullptr)) {
     295           0 :             WRITE_WARNING(TL("Environment variable SUMO_HOME is not set, could not find localized messages."));
     296           0 :             return;
     297             :         }
     298             :     } else {
     299       96672 :         const std::string path = sumoPath + std::string("/data/locale/");
     300       48336 :         if (!bindtextdomain("sumo", path.data())) {
     301           0 :             WRITE_WARNING(TL("Could not find localized messages."));
     302             :             return;
     303             :         }
     304             :     }
     305       48368 :     bind_textdomain_codeset("sumo", "UTF-8");
     306       48368 :     textdomain("sumo");
     307             : #else
     308             :     UNUSED_PARAMETER(locale);
     309             : #endif
     310       48368 :     myWarningPrefix = TL("Warning: ");
     311       48368 :     myErrorPrefix = TL("Error: ");
     312             : }
     313             : 
     314             : 
     315             : void
     316       43150 : MsgHandler::initOutputOptions() {
     317             :     // initialize console properly
     318       43150 :     OutputDevice::getDevice("stdout");
     319       43150 :     OutputDevice::getDevice("stderr");
     320       43150 :     OptionsCont& oc = OptionsCont::getOptions();
     321       43150 :     getWarningInstance()->setAggregationThreshold(oc.getInt("aggregate-warnings"));
     322       43150 :     getErrorInstance()->setAggregationThreshold(oc.getInt("aggregate-warnings"));
     323       86300 :     if (oc.getBool("no-warnings")) {
     324         168 :         getWarningInstance()->removeRetriever(&OutputDevice::getDevice("stderr"));
     325             :     }
     326             :     // build the logger if possible
     327       86300 :     if (oc.isSet("log", false)) {
     328         794 :         OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("log"));
     329         397 :         getErrorInstance()->addRetriever(logFile);
     330         794 :         if (!oc.getBool("no-warnings")) {
     331         397 :             getWarningInstance()->addRetriever(logFile);
     332             :         }
     333         397 :         getMessageInstance()->addRetriever(logFile);
     334         794 :         if (oc.getBool("log.timestamps")) {
     335           1 :             myWriteTimestamps = true;
     336             :         }
     337         794 :         if (oc.getBool("log.processid")) {
     338           1 :             myWriteProcessId = true;
     339             :         }
     340             :     }
     341       86300 :     if (oc.isSet("message-log", false)) {
     342       13278 :         OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("message-log"));
     343        6639 :         getMessageInstance()->addRetriever(logFile);
     344             :     }
     345       86300 :     if (oc.isSet("error-log", false)) {
     346       13348 :         OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("error-log"));
     347        6674 :         getErrorInstance()->addRetriever(logFile);
     348        6674 :         getWarningInstance()->addRetriever(logFile);
     349             :     }
     350       86300 :     if (oc.getBool("verbose")) {
     351        9288 :         getErrorInstance()->myInitialMessages.push_back("Repeating initial error messages:");
     352             :     } else {
     353       77012 :         getMessageInstance()->removeRetriever(&OutputDevice::getDevice("stdout"));
     354             :     }
     355       43150 : }
     356             : 
     357             : 
     358             : void
     359      121476 : MsgHandler::cleanupOnEnd() {
     360      121476 :     delete myMessageInstance;
     361      121476 :     myMessageInstance = nullptr;
     362      121476 :     delete myWarningInstance;
     363      121476 :     myWarningInstance = nullptr;
     364      121476 :     delete myErrorInstance;
     365      121476 :     myErrorInstance = nullptr;
     366      121476 :     delete myDebugInstance;
     367      121476 :     myDebugInstance = nullptr;
     368      121476 :     delete myGLDebugInstance;
     369      121476 :     myGLDebugInstance = nullptr;
     370      121476 : }
     371             : 
     372             : 
     373             : std::string
     374           5 : MsgHandler::buildTimestampPrefix(void) const {
     375           5 :     std::stringstream prefix;
     376           5 :     const std::chrono::system_clock::time_point now_timestamp = std::chrono::system_clock::now();
     377             :     const auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now_timestamp.time_since_epoch()) % 1000;
     378           5 :     const std::time_t now_time_t = std::chrono::system_clock::to_time_t(now_timestamp);
     379             : 
     380             :     char timeString[21];
     381           5 :     std::strftime(timeString, 21, "[%F %T", std::localtime(&now_time_t));
     382          10 :     prefix << timeString << '.' << std::setfill('0') << std::setw(3) << milliseconds.count() << "] ";
     383           5 :     return prefix.str();
     384           5 : }
     385             : 
     386             : 
     387             : std::string
     388           5 : MsgHandler::buildProcessIdPrefix(void) const {
     389           5 :     std::stringstream prefix;
     390           5 :     prefix << "[PID: ";
     391             : #ifdef WIN32
     392             :     prefix << GetCurrentProcessId();
     393             : #else
     394           5 :     prefix << getpid();
     395             : #endif
     396           5 :     prefix << "] ";
     397           5 :     return prefix.str();
     398           5 : }
     399             : 
     400             : 
     401      292734 : MsgHandler::MsgHandler(MsgType type) :
     402      292734 :     myType(type), myWasInformed(false), myAggregationThreshold(-1) {
     403      292734 :     if (type == MsgType::MT_MESSAGE) {
     404      143978 :         addRetriever(&OutputDevice::getDevice("stdout"));
     405             :     } else {
     406      441490 :         addRetriever(&OutputDevice::getDevice("stderr"));
     407             :     }
     408      292734 : }
     409             : 
     410             : 
     411      495293 : MsgHandler::~MsgHandler() {
     412      495293 : }
     413             : 
     414             : 
     415             : bool
     416      392367 : MsgHandler::wasInformed() const {
     417      392367 :     return myWasInformed;
     418             : }
     419             : 
     420             : 
     421             : /****************************************************************************/

Generated by: LCOV version 1.14