Eclipse SUMO - Simulation of Urban MObility
MsgHandler.cpp
Go to the documentation of this file.
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 /****************************************************************************/
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
40 #include "MsgHandler.h"
41 
42 
43 // ===========================================================================
44 // static member variables
45 // ===========================================================================
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 
67  if (myMessageInstance == nullptr) {
68  if (myFactory == nullptr) {
70  } else {
72  }
73  }
74  return myMessageInstance;
75 }
76 
77 
80  if (myWarningInstance == nullptr) {
81  if (myFactory == nullptr) {
83  } else {
85  }
86  }
87  return myWarningInstance;
88 }
89 
90 
93  if (myErrorInstance == nullptr) {
95  }
96  return myErrorInstance;
97 }
98 
99 
100 MsgHandler*
102  if (myDebugInstance == nullptr) {
104  }
105  return myDebugInstance;
106 }
107 
108 
109 MsgHandler*
111  if (myGLDebugInstance == nullptr) {
113  }
114  return myGLDebugInstance;
115 }
116 
117 
118 void
120  myWriteDebugMessages = enable;
121 }
122 
123 void
125  myWriteDebugGLMessages = enable;
126 }
127 
128 
129 std::string
130 MsgHandler::insertLineBreaks(std::string msg, int lineWidth) {
131  // TODO: check what FXFont::getTextWidth can do
132  //int textWidth = getApp()->getNormalFont()->getTextWidth
133  if ((int)msg.size() <= lineWidth) {
134  return msg;
135  }
136  size_t pos = 0;
137  size_t nextLineBreak = msg.find('\n');
138  size_t spaceAfterLine = msg.find(' ', lineWidth);
139  while (spaceAfterLine != std::string::npos) {
140  if (nextLineBreak == std::string::npos || nextLineBreak > spaceAfterLine) {
141  msg = msg.replace(spaceAfterLine, 1, "\n");
142  pos = spaceAfterLine + 1;
143  } else {
144  pos = nextLineBreak + 1;
145  }
146  spaceAfterLine = msg.find(' ', pos + lineWidth);
147  nextLineBreak = msg.find('\n', pos);
148  }
149  return msg;
150 }
151 
152 
153 void
154 MsgHandler::inform(std::string msg, bool addType) {
155  if (addType && !myInitialMessages.empty() && myInitialMessages.size() < 5) {
156  myInitialMessages.push_back(msg);
157  }
158  // beautify progress output
159  if (myAmProcessingProcess) {
160  myAmProcessingProcess = false;
162  }
163  msg = build(msg, addType);
164  // inform all receivers
165  for (auto i : myRetrievers) {
166  i->inform(msg);
167  }
168  // set the information that something occurred
169  myWasInformed = true;
170 }
171 
172 
173 void
174 MsgHandler::beginProcessMsg(std::string msg, bool addType) {
175  msg = build(msg, addType);
176  // inform all other receivers
177  for (auto i : myRetrievers) {
178  i->inform(msg, ' ');
179  myAmProcessingProcess = true;
180  }
181  // set the information that something occurred
182  myWasInformed = true;
183 }
184 
185 
186 void
187 MsgHandler::endProcessMsg2(bool success, long duration) {
188  if (success) {
189  if (duration > -1) {
190  endProcessMsg(TLF("done (%ms).", toString(duration)));
191  } else {
192  endProcessMsg(TL("done."));
193  }
194  } else {
195  endProcessMsg(TL("failed."));
196  }
197 }
198 
199 
200 void
201 MsgHandler::endProcessMsg(std::string msg) {
202  // inform all other receivers
203  for (auto i : myRetrievers) {
204  i->inform(msg);
205  }
206  // set the information that something occurred
207  myWasInformed = true;
208  myAmProcessingProcess = false;
209 }
210 
211 
212 void
213 MsgHandler::clear(bool resetInformed) {
214  if (myAggregationThreshold >= 0) {
215  for (const auto& i : myAggregationCount) {
216  if (i.second > myAggregationThreshold) {
217  inform(toString(i.second) + " total messages of type: " + i.first);
218  }
219  }
220  }
221  myAggregationCount.clear();
222  if (!resetInformed && myInitialMessages.size() > 1) {
223  const bool wasInformed = myWasInformed;
224  for (const std::string& msg : myInitialMessages) {
225  inform(msg, false);
226  }
227  myInitialMessages.clear();
229  }
230  if (resetInformed) {
231  myWasInformed = false;
232  }
233 }
234 
235 
236 void
238  if (!isRetriever(retriever)) {
239  myRetrievers.push_back(retriever);
240  }
241 }
242 
243 
244 void
246  std::vector<OutputDevice*>::iterator i = find(myRetrievers.begin(), myRetrievers.end(), retriever);
247  if (i != myRetrievers.end()) {
248  myRetrievers.erase(i);
249  }
250 }
251 
252 
253 bool
255  return std::find(myRetrievers.begin(), myRetrievers.end(), retriever) != myRetrievers.end();
256 }
257 
258 
259 void
261  if (myDebugInstance != nullptr) {
263  }
264  if (myGLDebugInstance != nullptr) {
266  }
267  if (myErrorInstance != nullptr) {
269  }
270  if (myWarningInstance != nullptr) {
272  }
273  if (myMessageInstance != nullptr) {
275  }
276 }
277 
278 
279 void
280 MsgHandler::setupI18n(const std::string& locale) {
281 #ifdef HAVE_INTL
282  if (locale != "") {
283 #ifdef WIN32
284  _putenv_s("LANGUAGE", locale.data());
285 #else
286  setenv("LANGUAGE", locale.data(), true);
287 #endif
288  }
289  if (!setlocale(LC_MESSAGES, "")) {
290  WRITE_WARNINGF(TL("Could not set locale to '%'."), locale);
291  }
292  const char* sumoPath = getenv("SUMO_HOME");
293  if (sumoPath == nullptr) {
294  if (!bindtextdomain("sumo", nullptr)) {
295  WRITE_WARNING(TL("Environment variable SUMO_HOME is not set, could not find localized messages."));
296  return;
297  }
298  } else {
299  const std::string path = sumoPath + std::string("/data/locale/");
300  if (!bindtextdomain("sumo", path.data())) {
301  WRITE_WARNING(TL("Could not find localized messages."));
302  return;
303  }
304  }
305  bind_textdomain_codeset("sumo", "UTF-8");
306  textdomain("sumo");
307 #else
308  UNUSED_PARAMETER(locale);
309 #endif
310  myWarningPrefix = TL("Warning: ");
311  myErrorPrefix = TL("Error: ");
312 }
313 
314 
315 void
317  // initialize console properly
318  OutputDevice::getDevice("stdout");
319  OutputDevice::getDevice("stderr");
321  getWarningInstance()->setAggregationThreshold(oc.getInt("aggregate-warnings"));
322  getErrorInstance()->setAggregationThreshold(oc.getInt("aggregate-warnings"));
323  if (oc.getBool("no-warnings")) {
325  }
326  // build the logger if possible
327  if (oc.isSet("log", false)) {
328  OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("log"));
329  getErrorInstance()->addRetriever(logFile);
330  if (!oc.getBool("no-warnings")) {
331  getWarningInstance()->addRetriever(logFile);
332  }
333  getMessageInstance()->addRetriever(logFile);
334  if (oc.getBool("log.timestamps")) {
335  myWriteTimestamps = true;
336  }
337  if (oc.getBool("log.processid")) {
338  myWriteProcessId = true;
339  }
340  }
341  if (oc.isSet("message-log", false)) {
342  OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("message-log"));
343  getMessageInstance()->addRetriever(logFile);
344  }
345  if (oc.isSet("error-log", false)) {
346  OutputDevice* logFile = &OutputDevice::getDevice(oc.getString("error-log"));
347  getErrorInstance()->addRetriever(logFile);
348  getWarningInstance()->addRetriever(logFile);
349  }
350  if (oc.getBool("verbose")) {
351  getErrorInstance()->myInitialMessages.push_back("Repeating initial error messages:");
352  } else {
354  }
355 }
356 
357 
358 void
360  delete myMessageInstance;
361  myMessageInstance = nullptr;
362  delete myWarningInstance;
363  myWarningInstance = nullptr;
364  delete myErrorInstance;
365  myErrorInstance = nullptr;
366  delete myDebugInstance;
367  myDebugInstance = nullptr;
368  delete myGLDebugInstance;
369  myGLDebugInstance = nullptr;
370 }
371 
372 
373 std::string
375  std::stringstream prefix;
376  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  const std::time_t now_time_t = std::chrono::system_clock::to_time_t(now_timestamp);
379 
380  char timeString[21];
381  std::strftime(timeString, 21, "[%F %T", std::localtime(&now_time_t));
382  prefix << timeString << '.' << std::setfill('0') << std::setw(3) << milliseconds.count() << "] ";
383  return prefix.str();
384 }
385 
386 
387 std::string
389  std::stringstream prefix;
390  prefix << "[PID: ";
391 #ifdef WIN32
392  prefix << GetCurrentProcessId();
393 #else
394  prefix << getpid();
395 #endif
396  prefix << "] ";
397  return prefix.str();
398 }
399 
400 
402  myType(type), myWasInformed(false), myAggregationThreshold(-1) {
403  if (type == MsgType::MT_MESSAGE) {
405  } else {
407  }
408 }
409 
410 
412 }
413 
414 
415 bool
417  return myWasInformed;
418 }
419 
420 
421 /****************************************************************************/
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:296
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:295
#define TL(string)
Definition: MsgHandler.h:315
#define TLF(string,...)
Definition: MsgHandler.h:317
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:30
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
virtual void addRetriever(OutputDevice *retriever)
Adds a further retriever to the instance responsible for a certain msg type.
Definition: MsgHandler.cpp:237
std::vector< std::string > myInitialMessages
storage for initial messages
Definition: MsgHandler.h:260
static MsgHandler * getGLDebugInstance()
Returns the instance to add GLdebug to.
Definition: MsgHandler.cpp:110
bool wasInformed() const
Returns the information whether any messages were added.
Definition: MsgHandler.cpp:416
std::string buildProcessIdPrefix(void) const
Definition: MsgHandler.cpp:388
static MsgHandler * getErrorInstance()
Returns the instance to add errors to.
Definition: MsgHandler.cpp:92
virtual void inform(std::string msg, bool addType=true)
adds a new error to the list
Definition: MsgHandler.cpp:154
std::string buildTimestampPrefix(void) const
Definition: MsgHandler.cpp:374
static void enableDebugGLMessages(bool enable)
enable/disable gl-debug messages
Definition: MsgHandler.cpp:124
static MsgHandler * myGLDebugInstance
The instance to handle glDebug.
Definition: MsgHandler.h:229
static std::string insertLineBreaks(std::string msg, int lineWidth)
reformats a long string to contain newline after a certain line length in px (depending on the curren...
Definition: MsgHandler.cpp:130
virtual void endProcessMsg(std::string msg)
Ends a process information.
Definition: MsgHandler.cpp:201
std::string build(const std::string &msg, bool addType)
Builds the string which includes the mml-message type.
Definition: MsgHandler.h:176
static Factory myFactory
The function to call for new MsgHandlers, nullptr means use default constructor.
Definition: MsgHandler.h:223
bool myWasInformed
information whether an output occurred at all
Definition: MsgHandler.h:248
static bool myWriteTimestamps
Whether to prefix every message with a time stamp.
Definition: MsgHandler.h:272
MsgHandler *(* Factory)(MsgType)
Definition: MsgHandler.h:60
static void setupI18n(const std::string &locale="")
set up gettext stuff
Definition: MsgHandler.cpp:280
static void initOutputOptions()
init output options
Definition: MsgHandler.cpp:316
static MsgHandler * myErrorInstance
The instance to handle errors.
Definition: MsgHandler.h:232
static MsgHandler * getDebugInstance()
Returns the instance to add debug to.
Definition: MsgHandler.cpp:101
static MsgHandler * myMessageInstance
The instance to handle normal messages.
Definition: MsgHandler.h:238
bool isRetriever(OutputDevice *retriever) const
Returns whether the given output device retrieves messages from the handler.
Definition: MsgHandler.cpp:254
static MsgHandler * getWarningInstance()
Returns the instance to add warnings to.
Definition: MsgHandler.cpp:79
std::map< const std::string, int > myAggregationCount
count for messages of the same type
Definition: MsgHandler.h:254
static void enableDebugMessages(bool enable)
enable/disable debug messages
Definition: MsgHandler.cpp:119
static bool myAmProcessingProcess
Information whether a process information is printed to cout.
Definition: MsgHandler.h:241
std::vector< OutputDevice * > myRetrievers
The list of retrievers that shall be informed about new messages or errors.
Definition: MsgHandler.h:257
virtual ~MsgHandler()
destructor
Definition: MsgHandler.cpp:411
virtual void clear(bool resetInformed=true)
Clears information whether an error occurred previously and print aggregated message summary.
Definition: MsgHandler.cpp:213
static MsgHandler * myDebugInstance
The instance to handle debug.
Definition: MsgHandler.h:226
void setAggregationThreshold(const int thresh)
Definition: MsgHandler.h:211
static MsgHandler * myWarningInstance
The instance to handle warnings.
Definition: MsgHandler.h:235
virtual void endProcessMsg2(bool success, long duration=-1)
Ends a process information with predefined messages.
Definition: MsgHandler.cpp:187
virtual void beginProcessMsg(std::string msg, bool addType=true)
Begins a process information.
Definition: MsgHandler.cpp:174
static bool myWriteDebugMessages
Flag to enable or disable debug output.
Definition: MsgHandler.h:266
static bool myWriteDebugGLMessages
Flag to enable or disable GL specific debug output.
Definition: MsgHandler.h:269
static std::string myWarningPrefix
The possibly translated warning prefix (mainly for speedup)
Definition: MsgHandler.h:281
static bool myWriteProcessId
Whether to prefix every message with the process id.
Definition: MsgHandler.h:275
static void cleanupOnEnd()
Removes pending handler.
Definition: MsgHandler.cpp:359
static std::string myErrorPrefix
The possibly translated error prefix (mainly for speedup)
Definition: MsgHandler.h:278
static void removeRetrieverFromAllInstances(OutputDevice *out)
ensure that that given output device is no longer used as retriever by any instance
Definition: MsgHandler.cpp:260
virtual void removeRetriever(OutputDevice *retriever)
Removes the retriever from the handler.
Definition: MsgHandler.cpp:245
int myAggregationThreshold
do not output more messages of the same type if the count exceeds this threshold
Definition: MsgHandler.h:251
@ MT_GLDEBUG
The message is GL debug output.
@ MT_DEBUG
The message is debug output.
@ MT_MESSAGE
The message is only something to show.
@ MT_ERROR
The message is an error.
@ MT_WARNING
The message is a warning.
MsgHandler(MsgType type)
standard constructor
Definition: MsgHandler.cpp:401
static MsgHandler * getMessageInstance()
Returns the instance to add normal messages to.
Definition: MsgHandler.cpp:66
A storage for options typed value containers)
Definition: OptionsCont.h:89
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:60
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:61
static OutputDevice & getDevice(const std::string &name, bool usePrefix=true)
Returns the described OutputDevice.