LCOV - code coverage report
Current view: top level - src/utils/common - MsgHandler.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 83.3 % 192 160
Test Date: 2024-11-22 15:46:21 Functions: 80.8 % 26 21

            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      1023950 : MsgHandler::getMessageInstance() {
      67      1023950 :     if (myMessageInstance == nullptr) {
      68        85086 :         if (myFactory == nullptr) {
      69        43792 :             myMessageInstance = new MsgHandler(MsgType::MT_MESSAGE);
      70              :         } else {
      71        41294 :             myMessageInstance = myFactory(MsgType::MT_MESSAGE);
      72              :         }
      73              :     }
      74      1023950 :     return myMessageInstance;
      75              : }
      76              : 
      77              : 
      78              : MsgHandler*
      79       949281 : MsgHandler::getWarningInstance() {
      80       949281 :     if (myWarningInstance == nullptr) {
      81       126359 :         if (myFactory == nullptr) {
      82        73729 :             myWarningInstance = new MsgHandler(MsgType::MT_WARNING);
      83              :         } else {
      84        52630 :             myWarningInstance = myFactory(MsgType::MT_WARNING);
      85              :         }
      86              :     }
      87       949281 :     return myWarningInstance;
      88              : }
      89              : 
      90              : 
      91              : MsgHandler*
      92      1401713 : MsgHandler::getErrorInstance() {
      93      1401713 :     if (myErrorInstance == nullptr) {
      94       126347 :         myErrorInstance = new MsgHandler(MsgType::MT_ERROR);
      95              :     }
      96      1401713 :     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            0 :         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            0 :     return msg;
     150              : }
     151              : 
     152              : 
     153              : void
     154      1103601 : MsgHandler::inform(std::string msg, bool addType) {
     155      1103601 :     if (addType && !myInitialMessages.empty() && myInitialMessages.size() < 5) {
     156           94 :         myInitialMessages.push_back(msg);
     157              :     }
     158              :     // beautify progress output
     159      1103601 :     if (myAmProcessingProcess) {
     160          742 :         myAmProcessingProcess = false;
     161         1484 :         MsgHandler::getMessageInstance()->inform("");
     162              :     }
     163      2207202 :     msg = build(msg, addType);
     164              :     // inform all receivers
     165      1693780 :     for (auto i : myRetrievers) {
     166       590179 :         i->inform(msg);
     167              :     }
     168              :     // set the information that something occurred
     169      1103601 :     myWasInformed = true;
     170      1103601 : }
     171              : 
     172              : 
     173              : void
     174       138739 : MsgHandler::beginProcessMsg(std::string msg, bool addType) {
     175       277478 :     msg = build(msg, addType);
     176              :     // inform all other receivers
     177       167349 :     for (auto i : myRetrievers) {
     178        28610 :         i->inform(msg, true);
     179        28610 :         myAmProcessingProcess = true;
     180              :     }
     181              :     // set the information that something occurred
     182       138739 :     myWasInformed = true;
     183       138739 : }
     184              : 
     185              : 
     186              : void
     187       137664 : MsgHandler::endProcessMsg2(bool success, long duration) {
     188       137664 :     if (success) {
     189       136937 :         if (duration > -1) {
     190       230832 :             endProcessMsg(TLF(" done (%ms).", toString(duration)));
     191              :         } else {
     192        43042 :             endProcessMsg(TL(" done."));
     193              :         }
     194              :     } else {
     195         1454 :         endProcessMsg(TL(" failed."));
     196              :     }
     197       137664 : }
     198              : 
     199              : 
     200              : void
     201       138255 : MsgHandler::endProcessMsg(std::string msg) {
     202              :     // inform all other receivers
     203       166672 :     for (auto i : myRetrievers) {
     204        28417 :         i->inform(msg);
     205              :     }
     206              :     // set the information that something occurred
     207       138255 :     myWasInformed = true;
     208       138255 :     myAmProcessingProcess = false;
     209       138255 : }
     210              : 
     211              : 
     212              : void
     213       401556 : MsgHandler::clear(bool resetInformed) {
     214       401556 :     if (myAggregationThreshold >= 0) {
     215         9575 :         for (const auto& i : myAggregationCount) {
     216         1666 :             if (i.second > myAggregationThreshold) {
     217          993 :                 inform(toString(i.second) + " total messages of type: " + i.first);
     218              :             }
     219              :         }
     220              :     }
     221              :     myAggregationCount.clear();
     222       401556 :     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       401556 :     if (resetInformed) {
     231       399238 :         myWasInformed = false;
     232              :     }
     233       401556 : }
     234              : 
     235              : 
     236              : void
     237       411461 : MsgHandler::addRetriever(OutputDevice* retriever) {
     238       411461 :     if (!isRetriever(retriever)) {
     239       411461 :         myRetrievers.push_back(retriever);
     240              :     }
     241       411461 : }
     242              : 
     243              : 
     244              : void
     245       997248 : MsgHandler::removeRetriever(OutputDevice* retriever) {
     246       997248 :     std::vector<OutputDevice*>::iterator i = find(myRetrievers.begin(), myRetrievers.end(), retriever);
     247       997248 :     if (i != myRetrievers.end()) {
     248       403829 :         myRetrievers.erase(i);
     249              :     }
     250       997248 : }
     251              : 
     252              : 
     253              : bool
     254       713904 : MsgHandler::isRetriever(OutputDevice* retriever) const {
     255       713904 :     return std::find(myRetrievers.begin(), myRetrievers.end(), retriever) != myRetrievers.end();
     256              : }
     257              : 
     258              : 
     259              : void
     260       277370 : MsgHandler::removeRetrieverFromAllInstances(OutputDevice* out) {
     261       277370 :     if (myDebugInstance != nullptr) {
     262            0 :         myDebugInstance->removeRetriever(out);
     263              :     }
     264       277370 :     if (myGLDebugInstance != nullptr) {
     265            0 :         myGLDebugInstance->removeRetriever(out);
     266              :     }
     267       277370 :     if (myErrorInstance != nullptr) {
     268       277370 :         myErrorInstance->removeRetriever(out);
     269              :     }
     270       277370 :     if (myWarningInstance != nullptr) {
     271       277370 :         myWarningInstance->removeRetriever(out);
     272              :     }
     273       277370 :     if (myMessageInstance != nullptr) {
     274       236085 :         myMessageInstance->removeRetriever(out);
     275              :     }
     276       277370 : }
     277              : 
     278              : 
     279              : void
     280        58064 : MsgHandler::setupI18n(const std::string& locale) {
     281              : #ifdef HAVE_INTL
     282        58064 :     if (locale != "") {
     283              : #ifdef WIN32
     284              :         _putenv_s("LANGUAGE", locale.data());
     285              : #else
     286        58064 :         setenv("LANGUAGE", locale.data(), true);
     287              : #endif
     288              :     }
     289        58064 :     if (!setlocale(LC_MESSAGES, "")) {
     290            0 :         WRITE_WARNINGF(TL("Could not set locale to '%'."), locale);
     291              :     }
     292        58064 :     const char* sumoPath = getenv("SUMO_HOME");
     293        58064 :     if (sumoPath == nullptr) {
     294           16 :         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       116096 :         const std::string path = sumoPath + std::string("/data/locale/");
     300        58048 :         if (!bindtextdomain("sumo", path.data())) {
     301            0 :             WRITE_WARNING(TL("Could not find localized messages."));
     302              :             return;
     303              :         }
     304              :     }
     305        58064 :     bind_textdomain_codeset("sumo", "UTF-8");
     306        58064 :     textdomain("sumo");
     307              : #else
     308              :     UNUSED_PARAMETER(locale);
     309              : #endif
     310        58064 :     myWarningPrefix = TL("Warning: ");
     311        58064 :     myErrorPrefix = TL("Error: ");
     312              : }
     313              : 
     314              : 
     315              : void
     316        55259 : MsgHandler::initOutputOptions() {
     317              :     // initialize console properly
     318        55259 :     OutputDevice::getDevice("stdout");
     319        55259 :     OutputDevice::getDevice("stderr");
     320        55259 :     OptionsCont& oc = OptionsCont::getOptions();
     321        55259 :     getWarningInstance()->setAggregationThreshold(oc.getInt("aggregate-warnings"));
     322        55259 :     getErrorInstance()->setAggregationThreshold(oc.getInt("aggregate-warnings"));
     323       110518 :     if (oc.getBool("no-warnings")) {
     324           88 :         getWarningInstance()->removeRetriever(&OutputDevice::getDevice("stderr"));
     325              :     }
     326              :     // build the logger if possible
     327       110518 :     if (oc.isSet("log", false)) {
     328          237 :         OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("log"));
     329          237 :         getErrorInstance()->addRetriever(logFile);
     330          474 :         if (!oc.getBool("no-warnings")) {
     331          237 :             getWarningInstance()->addRetriever(logFile);
     332              :         }
     333          237 :         getMessageInstance()->addRetriever(logFile);
     334          474 :         if (oc.getBool("log.timestamps")) {
     335            1 :             myWriteTimestamps = true;
     336              :         }
     337          474 :         if (oc.getBool("log.processid")) {
     338            1 :             myWriteProcessId = true;
     339              :         }
     340              :     }
     341       110518 :     if (oc.isSet("message-log", false)) {
     342         6965 :         OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("message-log"));
     343         6965 :         getMessageInstance()->addRetriever(logFile);
     344              :     }
     345       110518 :     if (oc.isSet("error-log", false)) {
     346         6983 :         OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("error-log"));
     347         6983 :         getErrorInstance()->addRetriever(logFile);
     348         6983 :         getWarningInstance()->addRetriever(logFile);
     349              :     }
     350       110518 :     if (oc.getBool("verbose")) {
     351         8766 :         getErrorInstance()->myInitialMessages.push_back("Repeating initial error messages:");
     352              :     } else {
     353       101752 :         getMessageInstance()->removeRetriever(&OutputDevice::getDevice("stdout"));
     354              :     }
     355        55259 : }
     356              : 
     357              : 
     358              : void
     359       137957 : MsgHandler::cleanupOnEnd() {
     360       137957 :     delete myMessageInstance;
     361       137957 :     myMessageInstance = nullptr;
     362       137957 :     delete myWarningInstance;
     363       137957 :     myWarningInstance = nullptr;
     364       137957 :     delete myErrorInstance;
     365       137957 :     myErrorInstance = nullptr;
     366       137957 :     delete myDebugInstance;
     367       137957 :     myDebugInstance = nullptr;
     368       137957 :     delete myGLDebugInstance;
     369       137957 :     myGLDebugInstance = nullptr;
     370       137957 : }
     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       337792 : MsgHandler::MsgHandler(MsgType type) :
     402       337792 :     myType(type), myWasInformed(false), myAggregationThreshold(-1) {
     403       337792 :     if (type == MsgType::MT_MESSAGE) {
     404       170172 :         addRetriever(&OutputDevice::getDevice("stdout"));
     405              :     } else {
     406       505412 :         addRetriever(&OutputDevice::getDevice("stderr"));
     407              :     }
     408       337792 : }
     409              : 
     410              : 
     411       581606 : MsgHandler::~MsgHandler() {
     412       581606 : }
     413              : 
     414              : 
     415              : bool
     416       332131 : MsgHandler::wasInformed() const {
     417       332131 :     return myWasInformed;
     418              : }
     419              : 
     420              : 
     421              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1