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: 2025-12-06 15:35:27 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-2025 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      1024777 : MsgHandler::getMessageInstance() {
      64      1024777 :     if (myMessageInstance == nullptr) {
      65        77612 :         if (myFactory == nullptr) {
      66        33667 :             myMessageInstance = new MsgHandler(MsgType::MT_MESSAGE);
      67              :         } else {
      68        43945 :             myMessageInstance = myFactory(MsgType::MT_MESSAGE);
      69              :         }
      70              :     }
      71      1024777 :     return myMessageInstance;
      72              : }
      73              : 
      74              : 
      75              : MsgHandler*
      76      1412639 : MsgHandler::getWarningInstance() {
      77      1412639 :     if (myWarningInstance == nullptr) {
      78       121774 :         if (myFactory == nullptr) {
      79        65725 :             myWarningInstance = new MsgHandler(MsgType::MT_WARNING);
      80              :         } else {
      81        56049 :             myWarningInstance = myFactory(MsgType::MT_WARNING);
      82              :         }
      83              :     }
      84      1412639 :     return myWarningInstance;
      85              : }
      86              : 
      87              : 
      88              : MsgHandler*
      89      5717779 : MsgHandler::getErrorInstance() {
      90      5717779 :     if (myErrorInstance == nullptr) {
      91       117423 :         myErrorInstance = new MsgHandler(MsgType::MT_ERROR);
      92              :     }
      93      5717779 :     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      5609307 : MsgHandler::inform(std::string msg, bool addType) {
     134      5609307 :     if (addType && !myInitialMessages.empty() && myInitialMessages.size() < 5) {
     135          226 :         myInitialMessages.push_back(msg);
     136              :     }
     137              :     // beautify progress output
     138      5609307 :     if (myAmProcessingProcess) {
     139          794 :         myAmProcessingProcess = false;
     140         1588 :         MsgHandler::getMessageInstance()->inform("");
     141              :     }
     142     11218614 :     msg = build(msg, addType);
     143              :     // inform all receivers
     144     10641385 :     for (auto i : myRetrievers) {
     145      5032078 :         i->inform(msg);
     146              :     }
     147              :     // set the information that something occurred
     148      5609307 :     myWasInformed = true;
     149      5609307 : }
     150              : 
     151              : 
     152              : void
     153       129078 : MsgHandler::beginProcessMsg(std::string msg, bool addType) {
     154       258156 :     msg = build(msg, addType);
     155              :     // inform all other receivers
     156       159773 :     for (auto i : myRetrievers) {
     157        30695 :         i->inform(msg, true);
     158        30695 :         myAmProcessingProcess = true;
     159              :     }
     160              :     // set the information that something occurred
     161       129078 :     myWasInformed = true;
     162       129078 : }
     163              : 
     164              : 
     165              : void
     166       127996 : MsgHandler::endProcessMsg2(bool success, long duration) {
     167       127996 :     if (success) {
     168       127269 :         if (duration > -1) {
     169       234450 :             endProcessMsg(TLF(" done (%ms).", toString(duration)));
     170              :         } else {
     171        20088 :             endProcessMsg(TL(" done."));
     172              :         }
     173              :     } else {
     174         1454 :         endProcessMsg(TL(" failed."));
     175              :     }
     176       127996 : }
     177              : 
     178              : 
     179              : void
     180       128650 : MsgHandler::endProcessMsg(std::string msg) {
     181              :     // inform all other receivers
     182       159175 :     for (auto i : myRetrievers) {
     183        30525 :         i->inform(msg);
     184              :     }
     185              :     // set the information that something occurred
     186       128650 :     myWasInformed = true;
     187       128650 :     myAmProcessingProcess = false;
     188       128650 : }
     189              : 
     190              : 
     191              : void
     192       366035 : MsgHandler::clear(bool resetInformed) {
     193       366035 :     if (myAggregationThreshold >= 0) {
     194        41129 :         for (const auto& i : myAggregationCount) {
     195         5196 :             if (i.second > myAggregationThreshold) {
     196        11412 :                 inform(toString(i.second) + " total messages of type: " + i.first);
     197              :             }
     198              :         }
     199              :     }
     200              :     myAggregationCount.clear();
     201       366035 :     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       366035 :     if (resetInformed) {
     210       363596 :         myWasInformed = false;
     211              :     }
     212       366035 : }
     213              : 
     214              : 
     215              : void
     216       395600 : MsgHandler::addRetriever(OutputDevice* retriever) {
     217       395600 :     if (!isRetriever(retriever)) {
     218       395600 :         myRetrievers.push_back(retriever);
     219              :     }
     220       395600 : }
     221              : 
     222              : 
     223              : void
     224       990220 : MsgHandler::removeRetriever(OutputDevice* retriever) {
     225       990220 :     std::vector<OutputDevice*>::iterator i = find(myRetrievers.begin(), myRetrievers.end(), retriever);
     226       990220 :     if (i != myRetrievers.end()) {
     227       383081 :         myRetrievers.erase(i);
     228              :     }
     229       990220 : }
     230              : 
     231              : 
     232              : bool
     233       700400 : MsgHandler::isRetriever(OutputDevice* retriever) const {
     234       700400 :     return std::find(myRetrievers.begin(), myRetrievers.end(), retriever) != myRetrievers.end();
     235              : }
     236              : 
     237              : 
     238              : void
     239       274548 : MsgHandler::removeRetrieverFromAllInstances(OutputDevice* out) {
     240       274548 :     if (myErrorInstance != nullptr) {
     241       274548 :         myErrorInstance->removeRetriever(out);
     242              :     }
     243       274548 :     if (myWarningInstance != nullptr) {
     244       274548 :         myWarningInstance->removeRetriever(out);
     245              :     }
     246       274548 :     if (myMessageInstance != nullptr) {
     247       234708 :         myMessageInstance->removeRetriever(out);
     248              :     }
     249       274548 : }
     250              : 
     251              : 
     252              : void
     253        48736 : MsgHandler::setupI18n(const std::string& locale) {
     254              : #ifdef HAVE_INTL
     255        48736 :     if (locale != "") {
     256              : #ifdef WIN32
     257              :         _putenv_s("LANGUAGE", locale.data());
     258              : #else
     259        48736 :         setenv("LANGUAGE", locale.data(), true);
     260              : #endif
     261              :     }
     262        48736 :     if (!setlocale(LC_MESSAGES, "")) {
     263            0 :         WRITE_WARNINGF(TL("Could not set locale to '%'."), locale);
     264              :     }
     265        48736 :     const char* sumoPath = getenv("SUMO_HOME");
     266        48736 :     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        97440 :         const std::string path = sumoPath + std::string("/data/locale/");
     273        48720 :         if (!bindtextdomain("sumo", path.data())) {
     274            0 :             WRITE_WARNING(TL("Could not find localized messages."));
     275              :             return;
     276              :         }
     277              :     }
     278        48736 :     bind_textdomain_codeset("sumo", "UTF-8");
     279        48736 :     textdomain("sumo");
     280              : #ifdef WIN32
     281              :     SetConsoleOutputCP(CP_UTF8);
     282              : #endif
     283              : #else
     284              :     UNUSED_PARAMETER(locale);
     285              : #endif
     286        48736 :     myWarningPrefix = TL("Warning: ");
     287        48736 :     myErrorPrefix = TL("Error: ");
     288        48736 :     gLocaleInitialized = true;
     289              : }
     290              : 
     291              : 
     292              : void
     293        45800 : MsgHandler::initOutputOptions() {
     294              :     // initialize console properly
     295        45800 :     OutputDevice::getDevice("stdout");
     296        45800 :     OutputDevice::getDevice("stderr");
     297        45800 :     OptionsCont& oc = OptionsCont::getOptions();
     298        45800 :     getWarningInstance()->setAggregationThreshold(oc.getInt("aggregate-warnings"));
     299        45800 :     getErrorInstance()->setAggregationThreshold(oc.getInt("aggregate-warnings"));
     300        91600 :     if (oc.getBool("no-warnings")) {
     301          570 :         getWarningInstance()->removeRetriever(&OutputDevice::getDevice("stderr"));
     302              :     }
     303              :     // build the logger if possible
     304        91600 :     if (oc.isSet("log", false)) {
     305          377 :         OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("log"));
     306          377 :         getErrorInstance()->addRetriever(logFile);
     307          754 :         if (!oc.getBool("no-warnings")) {
     308          377 :             getWarningInstance()->addRetriever(logFile);
     309              :         }
     310          377 :         getMessageInstance()->addRetriever(logFile);
     311          754 :         if (oc.getBool("log.timestamps")) {
     312            1 :             myWriteTimestamps = true;
     313              :         }
     314          754 :         if (oc.getBool("log.processid")) {
     315            1 :             myWriteProcessId = true;
     316              :         }
     317              :     }
     318        91600 :     if (oc.isSet("message-log", false)) {
     319         7410 :         OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("message-log"));
     320         7410 :         getMessageInstance()->addRetriever(logFile);
     321              :     }
     322        91600 :     if (oc.isSet("error-log", false)) {
     323         7441 :         OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("error-log"));
     324         7441 :         getErrorInstance()->addRetriever(logFile);
     325         7441 :         getWarningInstance()->addRetriever(logFile);
     326              :     }
     327        91600 :     if (oc.getBool("verbose")) {
     328         9856 :         getErrorInstance()->myInitialMessages.push_back("Repeating initial error messages:");
     329              :     } else {
     330        81744 :         getMessageInstance()->removeRetriever(&OutputDevice::getDevice("stdout"));
     331              :     }
     332        45800 : }
     333              : 
     334              : 
     335              : void
     336       129810 : MsgHandler::cleanupOnEnd() {
     337       129810 :     delete myMessageInstance;
     338       129810 :     myMessageInstance = nullptr;
     339       129810 :     delete myWarningInstance;
     340       129810 :     myWarningInstance = nullptr;
     341       129810 :     delete myErrorInstance;
     342       129810 :     myErrorInstance = nullptr;
     343       129810 : }
     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       316809 : MsgHandler::MsgHandler(MsgType type) :
     361       316809 :     myType(type), myWasInformed(false), myAggregationThreshold(-1) {
     362       316809 :     if (type == MsgType::MT_MESSAGE) {
     363       155224 :         addRetriever(&OutputDevice::getDevice("stdout"));
     364              :     } else {
     365       478394 :         addRetriever(&OutputDevice::getDevice("stderr"));
     366              :     }
     367       316809 : }
     368              : 
     369              : 
     370       533512 : MsgHandler::~MsgHandler() {
     371       533512 : }
     372              : 
     373              : 
     374              : bool
     375       453014 : MsgHandler::wasInformed() const {
     376       453014 :     return myWasInformed;
     377              : }
     378              : 
     379              : 
     380              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1