Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/common/MsgHandler.h
169678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2003-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.h
15
/// @author Daniel Krajzewicz
16
/// @author Michael Behrisch
17
/// @author Jakob Erdmann
18
/// @author Mirko Barthauer
19
/// @date Tue, 17 Jun 2003
20
///
21
// Retrieves messages about the process and gives them further to output
22
/****************************************************************************/
23
#pragma once
24
#include <config.h>
25
#include <string>
26
#include <vector>
27
#include <map>
28
#include <utils/common/StringUtils.h>
29
#include <utils/common/Translation.h>
30
#include <utils/iodevices/OutputDevice.h>
31
32
33
// ===========================================================================
34
// class definitions
35
// ===========================================================================
36
/**
37
* MsgHandler
38
*/
39
class MsgHandler {
40
public:
41
/**
42
* @enum MsgType
43
* An enumeration to differ between different types of messages
44
* (errors, warning and information)
45
*/
46
enum class MsgType {
47
/// The message is only something to show
48
MT_MESSAGE,
49
/// The message is a warning
50
MT_WARNING,
51
/// The message is an error
52
MT_ERROR,
53
/// The message is debug output
54
MT_DEBUG,
55
/// The message is GL debug output
56
MT_GLDEBUG
57
};
58
59
private:
60
typedef MsgHandler* (*Factory)(MsgType);
61
62
public:
63
/// @brief Sets the factory function to use for new MsgHandlers
64
static void setFactory(Factory func) {
65
// clean old instances
66
cleanupOnEnd();
67
myFactory = func;
68
}
69
70
/// @brief Returns the instance to add normal messages to
71
static MsgHandler* getMessageInstance();
72
73
/// @brief Returns the instance to add warnings to
74
static MsgHandler* getWarningInstance();
75
76
/// @brief Returns the instance to add errors to
77
static MsgHandler* getErrorInstance();
78
79
/// @brief enable/disable debug messages
80
static void enableDebugMessages(bool enable);
81
82
/// @brief enable/disable gl-debug messages
83
static void enableDebugGLMessages(bool enable);
84
85
/// @brief check whether to enable/disable debug messages
86
static inline bool writeDebugMessages() {
87
return myWriteDebugMessages;
88
}
89
90
/// @brief check whether to enable/disable gl-debug messages
91
static inline bool writeDebugGLMessages() {
92
return myWriteDebugGLMessages;
93
}
94
95
/// @brief reformats a long string to contain newline after a certain line length in px (depending on the current font)
96
static std::string insertLineBreaks(std::string msg, int lineWidth);
97
98
/// @brief ensure that that given output device is no longer used as retriever by any instance
99
static void removeRetrieverFromAllInstances(OutputDevice* out);
100
101
///@brief set up gettext stuff
102
static void setupI18n(const std::string& locale = "");
103
104
///@brief init output options
105
static void initOutputOptions();
106
107
/// @brief Removes pending handler
108
static void cleanupOnEnd();
109
110
/// @brief adds a new error to the list
111
virtual void inform(std::string msg, bool addType = true);
112
113
/// @brief adds a new formatted message
114
// variadic function
115
template<typename T, typename... Targs>
116
void informf(const std::string& format, T value, Targs... Fargs) {
117
if (!aggregationThresholdReached(format)) {
118
inform(StringUtils::format(format, value, Fargs...), true);
119
}
120
}
121
122
/** @brief Begins a process information
123
*
124
* When a longer action is started, this method should be used to inform the user about it.
125
* There will be no newline printed, but the message handler will be informed that
126
* a process message has been begun. If an error occurs, a newline will be printed.
127
* After the action has been performed, use endProcessMsg to inform the user about it.
128
*/
129
virtual void beginProcessMsg(std::string msg, bool addType = true);
130
131
/// @brief Ends a process information with predefined messages
132
virtual void endProcessMsg2(bool success, long duration = -1);
133
134
/// @brief Ends a process information
135
virtual void endProcessMsg(std::string msg);
136
137
/// @brief Clears information whether an error occurred previously and print aggregated message summary
138
virtual void clear(bool resetInformed = true);
139
140
/// @brief Adds a further retriever to the instance responsible for a certain msg type
141
virtual void addRetriever(OutputDevice* retriever);
142
143
/// @brief Removes the retriever from the handler
144
virtual void removeRetriever(OutputDevice* retriever);
145
146
/// @brief Returns whether the given output device retrieves messages from the handler
147
bool isRetriever(OutputDevice* retriever) const;
148
149
/// @brief Returns the information whether any messages were added
150
bool wasInformed() const;
151
152
/** @brief Generic output operator
153
* @return The MsgHandler for further processing
154
*/
155
template <class T>
156
MsgHandler& operator<<(const T& t) {
157
// inform all other receivers
158
for (OutputDevice* o : myRetrievers) {
159
(*o) << t;
160
}
161
return *this;
162
}
163
164
void setAggregationThreshold(const int thresh) {
165
myAggregationThreshold = thresh;
166
}
167
168
int getAggregationThreshold() const {
169
return myAggregationThreshold;
170
}
171
172
protected:
173
174
std::string buildProcessIdPrefix() const;
175
176
/// @brief Builds the string which includes the mml-message type
177
inline std::string build(const std::string& msg, bool addType) {
178
std::string prefix;
179
if (myWriteTimestamps) {
180
prefix += "[" + StringUtils::isoTimeString() + "] ";
181
}
182
if (myWriteProcessId) {
183
prefix += buildProcessIdPrefix();
184
}
185
if (addType) {
186
switch (myType) {
187
case MsgType::MT_MESSAGE:
188
break;
189
case MsgType::MT_WARNING:
190
prefix += myWarningPrefix;
191
break;
192
case MsgType::MT_ERROR:
193
prefix += myErrorPrefix;
194
break;
195
case MsgType::MT_DEBUG:
196
prefix += "Debug: ";
197
break;
198
case MsgType::MT_GLDEBUG:
199
prefix += "GLDebug: ";
200
break;
201
default:
202
break;
203
}
204
}
205
return prefix + msg;
206
}
207
208
virtual bool aggregationThresholdReached(const std::string& format) {
209
return myAggregationThreshold >= 0 && myAggregationCount[format]++ >= myAggregationThreshold;
210
}
211
212
/// @brief standard constructor
213
MsgHandler(MsgType type);
214
215
/// @brief destructor
216
virtual ~MsgHandler();
217
218
private:
219
/// @brief The function to call for new MsgHandlers, nullptr means use default constructor
220
static Factory myFactory;
221
222
/// @brief The instance to handle errors
223
static MsgHandler* myErrorInstance;
224
225
/// @brief The instance to handle warnings
226
static MsgHandler* myWarningInstance;
227
228
/// @brief The instance to handle normal messages
229
static MsgHandler* myMessageInstance;
230
231
/// @brief Information whether a process information is printed to cout
232
static bool myAmProcessingProcess;
233
234
private:
235
/// @brief The type of the instance
236
MsgType myType;
237
238
/// @brief information whether an output occurred at all
239
bool myWasInformed;
240
241
/// @brief do not output more messages of the same type if the count exceeds this threshold
242
int myAggregationThreshold;
243
244
/// @brief count for messages of the same type
245
std::map<const std::string, int> myAggregationCount;
246
247
/// @brief The list of retrievers that shall be informed about new messages or errors
248
std::vector<OutputDevice*> myRetrievers;
249
250
/// @brief storage for initial messages
251
std::vector<std::string> myInitialMessages;
252
253
/** @brief Flag to enable or disable debug output
254
*
255
* This value is used to show more internal information through warning messages about certain operations
256
*/
257
static bool myWriteDebugMessages;
258
259
/// @brief Flag to enable or disable GL specific debug output
260
static bool myWriteDebugGLMessages;
261
262
/// @brief Whether to prefix every message with a time stamp
263
static bool myWriteTimestamps;
264
265
/// @brief Whether to prefix every message with the process id
266
static bool myWriteProcessId;
267
268
/// @brief The possibly translated error prefix (mainly for speedup)
269
static std::string myErrorPrefix;
270
271
/// @brief The possibly translated warning prefix (mainly for speedup)
272
static std::string myWarningPrefix;
273
274
private:
275
/// @brief invalid copy constructor
276
MsgHandler(const MsgHandler& s) = delete;
277
278
/// @brief invalid assignment operator
279
MsgHandler& operator=(const MsgHandler& s) = delete;
280
};
281
282
283
// ===========================================================================
284
// global definitions
285
// ===========================================================================
286
#define WRITE_WARNING(msg) MsgHandler::getWarningInstance()->inform(msg);
287
#define WRITE_WARNINGF(...) MsgHandler::getWarningInstance()->informf(__VA_ARGS__);
288
#define WRITE_MESSAGE(msg) MsgHandler::getMessageInstance()->inform(msg);
289
#define WRITE_MESSAGEF(...) MsgHandler::getMessageInstance()->informf(__VA_ARGS__);
290
#define PROGRESS_BEGIN_MESSAGE(msg) MsgHandler::getMessageInstance()->beginProcessMsg((msg) + std::string(" ..."));
291
#define PROGRESS_DONE_MESSAGE() MsgHandler::getMessageInstance()->endProcessMsg2(true);
292
#define PROGRESS_BEGIN_TIME_MESSAGE(msg) SysUtils::getCurrentMillis(); MsgHandler::getMessageInstance()->beginProcessMsg((msg) + std::string(" ..."));
293
#define PROGRESS_TIME_MESSAGE(before) MsgHandler::getMessageInstance()->endProcessMsg2(true, SysUtils::getCurrentMillis() - before);
294
#define PROGRESS_FAILED_MESSAGE() MsgHandler::getMessageInstance()->endProcessMsg2(false);
295
#define WRITE_ERROR(msg) MsgHandler::getErrorInstance()->inform(msg);
296
#define WRITE_ERRORF(...) MsgHandler::getErrorInstance()->informf(__VA_ARGS__);
297
#ifdef HAVE_INTL
298
// basic translation
299
#define TL(string) gettext(string)
300
// complex translation ("This % an %", "is", "example")
301
#define TLF(string, ...) StringUtils::format(gettext(string), __VA_ARGS__)
302
#else
303
// basic translation
304
#define TL(string) (string)
305
// complex translation ("This % an %", "is", "example")
306
#define TLF(string, ...) StringUtils::format(string, __VA_ARGS__)
307
#endif
308
309