LCOV - code coverage report
Current view: top level - src/utils/common - MsgHandler.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 87.0 % 169 147
Test Date: 2026-03-02 16:00:03 Functions: 87.0 % 23 20

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2026 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              : #ifdef WIN32
      30              : #define NOMINMAX
      31              : #include <windows.h>
      32              : #undef NOMINMAX
      33              : #else
      34              : #include <unistd.h>
      35              : #endif
      36              : #include <utils/options/OptionsCont.h>
      37              : #include <utils/iodevices/OutputDevice.h>
      38              : #include <utils/common/UtilExceptions.h>
      39              : #include "MsgHandler.h"
      40              : 
      41              : 
      42              : // ===========================================================================
      43              : // static member variables
      44              : // ===========================================================================
      45              : MsgHandler::Factory MsgHandler::myFactory = nullptr;
      46              : MsgHandler* MsgHandler::myErrorInstance = nullptr;
      47              : MsgHandler* MsgHandler::myWarningInstance = nullptr;
      48              : MsgHandler* MsgHandler::myMessageInstance = nullptr;
      49              : bool MsgHandler::myAmProcessingProcess = false;
      50              : bool MsgHandler::myWriteDebugMessages = false;
      51              : bool MsgHandler::myWriteDebugGLMessages = false;
      52              : bool MsgHandler::myWriteTimestamps = false;
      53              : bool MsgHandler::myWriteProcessId = false;
      54              : std::string MsgHandler::myErrorPrefix = "Error: ";
      55              : std::string MsgHandler::myWarningPrefix = "Warning: ";
      56              : 
      57              : 
      58              : // ===========================================================================
      59              : // method definitions
      60              : // ===========================================================================
      61              : 
      62              : MsgHandler*
      63      1063262 : MsgHandler::getMessageInstance() {
      64      1063262 :     if (myMessageInstance == nullptr) {
      65        81518 :         if (myFactory == nullptr) {
      66        35361 :             myMessageInstance = new MsgHandler(MsgType::MT_MESSAGE);
      67              :         } else {
      68        46157 :             myMessageInstance = myFactory(MsgType::MT_MESSAGE);
      69              :         }
      70              :     }
      71      1063262 :     return myMessageInstance;
      72              : }
      73              : 
      74              : 
      75              : MsgHandler*
      76      1556487 : MsgHandler::getWarningInstance() {
      77      1556487 :     if (myWarningInstance == nullptr) {
      78       128232 :         if (myFactory == nullptr) {
      79        69471 :             myWarningInstance = new MsgHandler(MsgType::MT_WARNING);
      80              :         } else {
      81        58761 :             myWarningInstance = myFactory(MsgType::MT_WARNING);
      82              :         }
      83              :     }
      84      1556487 :     return myWarningInstance;
      85              : }
      86              : 
      87              : 
      88              : MsgHandler*
      89      5819924 : MsgHandler::getErrorInstance() {
      90      5819924 :     if (myErrorInstance == nullptr) {
      91       123815 :         myErrorInstance = new MsgHandler(MsgType::MT_ERROR);
      92              :     }
      93      5819924 :     return myErrorInstance;
      94              : }
      95              : 
      96              : 
      97              : void
      98            0 : MsgHandler::enableDebugMessages(bool enable) {
      99            0 :     myWriteDebugMessages = enable;
     100            0 : }
     101              : 
     102              : void
     103            0 : MsgHandler::enableDebugGLMessages(bool enable) {
     104            0 :     myWriteDebugGLMessages = enable;
     105            0 : }
     106              : 
     107              : 
     108              : std::string
     109            0 : MsgHandler::insertLineBreaks(std::string msg, int lineWidth) {
     110              :     // TODO: check what FXFont::getTextWidth can do
     111              :     //int textWidth = getApp()->getNormalFont()->getTextWidth
     112            0 :     if ((int)msg.size() <= lineWidth) {
     113            0 :         return msg;
     114              :     }
     115              :     size_t pos = 0;
     116            0 :     size_t nextLineBreak = msg.find('\n');
     117            0 :     size_t spaceAfterLine = msg.find(' ', lineWidth);
     118            0 :     while (spaceAfterLine != std::string::npos) {
     119            0 :         if (nextLineBreak == std::string::npos || nextLineBreak > spaceAfterLine) {
     120              :             msg = msg.replace(spaceAfterLine, 1, "\n");
     121            0 :             pos = spaceAfterLine + 1;
     122              :         } else {
     123            0 :             pos = nextLineBreak + 1;
     124              :         }
     125            0 :         spaceAfterLine = msg.find(' ', pos + lineWidth);
     126            0 :         nextLineBreak = msg.find('\n', pos);
     127              :     }
     128            0 :     return msg;
     129              : }
     130              : 
     131              : 
     132              : void
     133      5790914 : MsgHandler::inform(std::string msg, bool addType) {
     134      5790914 :     if (addType && !myInitialMessages.empty() && myInitialMessages.size() < 5) {
     135          228 :         myInitialMessages.push_back(msg);
     136              :     }
     137              :     // beautify progress output
     138      5790914 :     if (myAmProcessingProcess) {
     139          821 :         myAmProcessingProcess = false;
     140         1642 :         MsgHandler::getMessageInstance()->inform("");
     141              :     }
     142     11581828 :     msg = build(msg, addType);
     143              :     // inform all receivers
     144     10991447 :     for (auto i : myRetrievers) {
     145      5200533 :         i->inform(msg);
     146              :     }
     147              :     // set the information that something occurred
     148      5790914 :     myWasInformed = true;
     149      5790914 : }
     150              : 
     151              : 
     152              : void
     153       135901 : MsgHandler::beginProcessMsg(std::string msg, bool addType) {
     154       271802 :     msg = build(msg, addType);
     155              :     // inform all other receivers
     156       168034 :     for (auto i : myRetrievers) {
     157        32133 :         i->inform(msg, true);
     158        32133 :         myAmProcessingProcess = true;
     159              :     }
     160              :     // set the information that something occurred
     161       135901 :     myWasInformed = true;
     162       135901 : }
     163              : 
     164              : 
     165              : void
     166       134805 : MsgHandler::endProcessMsg2(bool success, long duration) {
     167       134805 :     if (success) {
     168       134078 :         if (duration > -1) {
     169       247732 :             endProcessMsg(TLF(" done (%ms).", toString(duration)));
     170              :         } else {
     171        20424 :             endProcessMsg(TL(" done."));
     172              :         }
     173              :     } else {
     174         1454 :         endProcessMsg(TL(" failed."));
     175              :     }
     176       134805 : }
     177              : 
     178              : 
     179              : void
     180       135483 : MsgHandler::endProcessMsg(std::string msg) {
     181              :     // inform all other receivers
     182       167439 :     for (auto i : myRetrievers) {
     183        31956 :         i->inform(msg);
     184              :     }
     185              :     // set the information that something occurred
     186       135483 :     myWasInformed = true;
     187       135483 :     myAmProcessingProcess = false;
     188       135483 : }
     189              : 
     190              : 
     191              : void
     192       393718 : MsgHandler::clear(bool resetInformed) {
     193       393718 :     if (myAggregationThreshold >= 0) {
     194        41463 :         for (const auto& i : myAggregationCount) {
     195         5138 :             if (i.second > myAggregationThreshold) {
     196        11052 :                 inform(toString(i.second) + " total messages of type: " + i.first);
     197              :             }
     198              :         }
     199              :     }
     200              :     myAggregationCount.clear();
     201       393718 :     if (!resetInformed && myInitialMessages.size() > 1) {
     202            3 :         const bool wasInformed = myWasInformed;
     203           15 :         for (const std::string& msg : myInitialMessages) {
     204           24 :             inform(msg, false);
     205              :         }
     206              :         myInitialMessages.clear();
     207            3 :         myWasInformed = wasInformed;
     208              :     }
     209       393718 :     if (resetInformed) {
     210       391251 :         myWasInformed = false;
     211              :     }
     212       393718 : }
     213              : 
     214              : 
     215              : void
     216       416599 : MsgHandler::addRetriever(OutputDevice* retriever) {
     217       416599 :     if (!isRetriever(retriever)) {
     218       416599 :         myRetrievers.push_back(retriever);
     219              :     }
     220       416599 : }
     221              : 
     222              : 
     223              : void
     224      1048967 : MsgHandler::removeRetriever(OutputDevice* retriever) {
     225      1048967 :     std::vector<OutputDevice*>::iterator i = find(myRetrievers.begin(), myRetrievers.end(), retriever);
     226      1048967 :     if (i != myRetrievers.end()) {
     227       403599 :         myRetrievers.erase(i);
     228              :     }
     229      1048967 : }
     230              : 
     231              : 
     232              : bool
     233       740117 : MsgHandler::isRetriever(OutputDevice* retriever) const {
     234       740117 :     return std::find(myRetrievers.begin(), myRetrievers.end(), retriever) != myRetrievers.end();
     235              : }
     236              : 
     237              : 
     238              : void
     239       291297 : MsgHandler::removeRetrieverFromAllInstances(OutputDevice* out) {
     240       291297 :     if (myErrorInstance != nullptr) {
     241       291297 :         myErrorInstance->removeRetriever(out);
     242              :     }
     243       291297 :     if (myWarningInstance != nullptr) {
     244       291297 :         myWarningInstance->removeRetriever(out);
     245              :     }
     246       291297 :     if (myMessageInstance != nullptr) {
     247       248971 :         myMessageInstance->removeRetriever(out);
     248              :     }
     249       291297 : }
     250              : 
     251              : 
     252              : void
     253        50923 : MsgHandler::setupI18n(const std::string& locale) {
     254              : #ifdef HAVE_INTL
     255        50923 :     if (locale != "") {
     256              : #ifdef WIN32
     257              :         _putenv_s("LANGUAGE", locale.data());
     258              : #else
     259        50923 :         setenv("LANGUAGE", locale.data(), true);
     260              : #endif
     261              :     }
     262        50923 :     if (!setlocale(LC_MESSAGES, "")) {
     263            0 :         WRITE_WARNINGF(TL("Could not set locale to '%'."), locale);
     264              :     }
     265        50923 :     const char* sumoPath = getenv("SUMO_HOME");
     266        50923 :     if (sumoPath == nullptr) {
     267           16 :         if (!bindtextdomain("sumo", nullptr)) {
     268            0 :             WRITE_WARNING(TL("Environment variable SUMO_HOME is not set, could not find localized messages."));
     269            0 :             return;
     270              :         }
     271              :     } else {
     272       101814 :         const std::string path = sumoPath + std::string("/data/locale/");
     273        50907 :         if (!bindtextdomain("sumo", path.data())) {
     274            0 :             WRITE_WARNING(TL("Could not find localized messages."));
     275              :             return;
     276              :         }
     277              :     }
     278        50923 :     bind_textdomain_codeset("sumo", "UTF-8");
     279        50923 :     textdomain("sumo");
     280              : #ifdef WIN32
     281              :     SetConsoleOutputCP(CP_UTF8);
     282              : #endif
     283              : #else
     284              :     UNUSED_PARAMETER(locale);
     285              : #endif
     286        50923 :     myWarningPrefix = TL("Warning: ");
     287        50923 :     myErrorPrefix = TL("Error: ");
     288        50923 :     gLocaleInitialized = true;
     289              : }
     290              : 
     291              : 
     292              : void
     293        47990 : MsgHandler::initOutputOptions() {
     294              :     // initialize console properly
     295        47990 :     OutputDevice::getDevice("stdout");
     296        47990 :     OutputDevice::getDevice("stderr");
     297        47990 :     OptionsCont& oc = OptionsCont::getOptions();
     298        47990 :     getWarningInstance()->setAggregationThreshold(oc.getInt("aggregate-warnings"));
     299        47990 :     getErrorInstance()->setAggregationThreshold(oc.getInt("aggregate-warnings"));
     300        95980 :     if (oc.getBool("no-warnings")) {
     301          582 :         getWarningInstance()->removeRetriever(&OutputDevice::getDevice("stderr"));
     302              :     }
     303              :     // build the logger if possible
     304        95980 :     if (oc.isSet("log", false)) {
     305          389 :         OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("log"));
     306          389 :         getErrorInstance()->addRetriever(logFile);
     307          778 :         if (!oc.getBool("no-warnings")) {
     308          389 :             getWarningInstance()->addRetriever(logFile);
     309              :         }
     310          389 :         getMessageInstance()->addRetriever(logFile);
     311          778 :         if (oc.getBool("log.timestamps")) {
     312            1 :             myWriteTimestamps = true;
     313              :         }
     314          778 :         if (oc.getBool("log.processid")) {
     315            1 :             myWriteProcessId = true;
     316              :         }
     317              :     }
     318        95980 :     if (oc.isSet("message-log", false)) {
     319         7830 :         OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("message-log"));
     320         7830 :         getMessageInstance()->addRetriever(logFile);
     321              :     }
     322        95980 :     if (oc.isSet("error-log", false)) {
     323         7861 :         OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("error-log"));
     324         7861 :         getErrorInstance()->addRetriever(logFile);
     325         7861 :         getWarningInstance()->addRetriever(logFile);
     326              :     }
     327        95980 :     if (oc.getBool("verbose")) {
     328        10270 :         getErrorInstance()->myInitialMessages.push_back("Repeating initial error messages:");
     329              :     } else {
     330        85710 :         getMessageInstance()->removeRetriever(&OutputDevice::getDevice("stdout"));
     331              :     }
     332        47990 : }
     333              : 
     334              : 
     335              : void
     336       136701 : MsgHandler::cleanupOnEnd() {
     337       136701 :     delete myMessageInstance;
     338       136701 :     myMessageInstance = nullptr;
     339       136701 :     delete myWarningInstance;
     340       136701 :     myWarningInstance = nullptr;
     341       136701 :     delete myErrorInstance;
     342       136701 :     myErrorInstance = nullptr;
     343       136701 : }
     344              : 
     345              : 
     346              : std::string
     347            6 : MsgHandler::buildProcessIdPrefix() const {
     348            6 :     std::stringstream prefix;
     349            6 :     prefix << "[PID: ";
     350              : #ifdef WIN32
     351              :     prefix << GetCurrentProcessId();
     352              : #else
     353            6 :     prefix << getpid();
     354              : #endif
     355            6 :     prefix << "] ";
     356            6 :     return prefix.str();
     357            6 : }
     358              : 
     359              : 
     360       333565 : MsgHandler::MsgHandler(MsgType type) :
     361       333565 :     myType(type), myWasInformed(false), myAggregationThreshold(-1) {
     362       333565 :     if (type == MsgType::MT_MESSAGE) {
     363       163036 :         addRetriever(&OutputDevice::getDevice("stdout"));
     364              :     } else {
     365       504094 :         addRetriever(&OutputDevice::getDevice("stderr"));
     366              :     }
     367       333565 : }
     368              : 
     369              : 
     370       562112 : MsgHandler::~MsgHandler() {
     371       562112 : }
     372              : 
     373              : 
     374              : bool
     375       468533 : MsgHandler::wasInformed() const {
     376       468533 :     return myWasInformed;
     377              : }
     378              : 
     379              : 
     380              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1