Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2003-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.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 11623 : cleanupOnEnd();
67 11623 : myFactory = func;
68 4060 : }
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 Returns the instance to add debug to
80 : static MsgHandler* getDebugInstance();
81 :
82 : /// @brief Returns the instance to add GLdebug to
83 : static MsgHandler* getGLDebugInstance();
84 :
85 : /// @brief enable/disable debug messages
86 : static void enableDebugMessages(bool enable);
87 :
88 : /// @brief enable/disable gl-debug messages
89 : static void enableDebugGLMessages(bool enable);
90 :
91 : /// @brief check whether to enable/disable debug messages
92 : static inline bool writeDebugMessages() {
93 1467 : return myWriteDebugMessages;
94 : }
95 :
96 : /// @brief check whether to enable/disable gl-debug messages
97 : static inline bool writeDebugGLMessages() {
98 61456 : return myWriteDebugGLMessages;
99 : }
100 :
101 : /// @brief reformats a long string to contain newline after a certain line length in px (depending on the current font)
102 : static std::string insertLineBreaks(std::string msg, int lineWidth);
103 :
104 : /// @brief ensure that that given output device is no longer used as retriever by any instance
105 : static void removeRetrieverFromAllInstances(OutputDevice* out);
106 :
107 : ///@brief set up gettext stuff
108 : static void setupI18n(const std::string& locale = "");
109 :
110 : ///@brief init output options
111 : static void initOutputOptions();
112 :
113 : /// @brief Removes pending handler
114 : static void cleanupOnEnd();
115 :
116 : /// @brief adds a new error to the list
117 : virtual void inform(std::string msg, bool addType = true);
118 :
119 : /// @brief adds a new formatted message
120 : // variadic function
121 : template<typename T, typename... Targs>
122 429989 : void informf(const std::string& format, T value, Targs... Fargs) {
123 429989 : if (!aggregationThresholdReached(format)) {
124 1150823 : inform(StringUtils::format(format, value, Fargs...), true);
125 : }
126 429989 : }
127 :
128 : /** @brief Begins a process information
129 : *
130 : * When a longer action is started, this method should be used to inform the user about it.
131 : * There will be no newline printed, but the message handler will be informed that
132 : * a process message has been begun. If an error occurs, a newline will be printed.
133 : * After the action has been performed, use endProcessMsg to inform the user about it.
134 : */
135 : virtual void beginProcessMsg(std::string msg, bool addType = true);
136 :
137 : /// @brief Ends a process information with predefined messages
138 : virtual void endProcessMsg2(bool success, long duration = -1);
139 :
140 : /// @brief Ends a process information
141 : virtual void endProcessMsg(std::string msg);
142 :
143 : /// @brief Clears information whether an error occurred previously and print aggregated message summary
144 : virtual void clear(bool resetInformed = true);
145 :
146 : /// @brief Adds a further retriever to the instance responsible for a certain msg type
147 : virtual void addRetriever(OutputDevice* retriever);
148 :
149 : /// @brief Removes the retriever from the handler
150 : virtual void removeRetriever(OutputDevice* retriever);
151 :
152 : /// @brief Returns whether the given output device retrieves messages from the handler
153 : bool isRetriever(OutputDevice* retriever) const;
154 :
155 : /// @brief Returns the information whether any messages were added
156 : bool wasInformed() const;
157 :
158 : /** @brief Generic output operator
159 : * @return The MsgHandler for further processing
160 : */
161 : template <class T>
162 : MsgHandler& operator<<(const T& t) {
163 : // inform all other receivers
164 : for (OutputDevice* o : myRetrievers) {
165 : (*o) << t;
166 : }
167 : return *this;
168 : }
169 :
170 : protected:
171 :
172 : std::string buildTimestampPrefix(void) const;
173 : std::string buildProcessIdPrefix(void) const;
174 :
175 : /// @brief Builds the string which includes the mml-message type
176 1242340 : inline std::string build(const std::string& msg, bool addType) {
177 : std::string prefix;
178 1242340 : if (myWriteTimestamps) {
179 10 : prefix += buildTimestampPrefix();
180 : }
181 1242340 : if (myWriteProcessId) {
182 10 : prefix += buildProcessIdPrefix();
183 : }
184 1242340 : if (addType) {
185 1232932 : switch (myType) {
186 : case MsgType::MT_MESSAGE:
187 : break;
188 : case MsgType::MT_WARNING:
189 : prefix += myWarningPrefix;
190 : break;
191 : case MsgType::MT_ERROR:
192 : prefix += myErrorPrefix;
193 : break;
194 : case MsgType::MT_DEBUG:
195 : prefix += "Debug: ";
196 : break;
197 : case MsgType::MT_GLDEBUG:
198 : prefix += "GLDebug: ";
199 : break;
200 : default:
201 : break;
202 : }
203 : }
204 1242340 : return prefix + msg;
205 : }
206 :
207 429989 : virtual bool aggregationThresholdReached(const std::string& format) {
208 429989 : return myAggregationThreshold >= 0 && myAggregationCount[format]++ >= myAggregationThreshold;
209 : }
210 :
211 : void setAggregationThreshold(const int thresh) {
212 110518 : myAggregationThreshold = thresh;
213 : }
214 :
215 : /// @brief standard constructor
216 : MsgHandler(MsgType type);
217 :
218 : /// @brief destructor
219 : virtual ~MsgHandler();
220 :
221 : private:
222 : /// @brief The function to call for new MsgHandlers, nullptr means use default constructor
223 : static Factory myFactory;
224 :
225 : /// @brief The instance to handle debug
226 : static MsgHandler* myDebugInstance;
227 :
228 : /// @brief The instance to handle glDebug
229 : static MsgHandler* myGLDebugInstance;
230 :
231 : /// @brief The instance to handle errors
232 : static MsgHandler* myErrorInstance;
233 :
234 : /// @brief The instance to handle warnings
235 : static MsgHandler* myWarningInstance;
236 :
237 : /// @brief The instance to handle normal messages
238 : static MsgHandler* myMessageInstance;
239 :
240 : /// @brief Information whether a process information is printed to cout
241 : static bool myAmProcessingProcess;
242 :
243 : private:
244 : /// @brief The type of the instance
245 : MsgType myType;
246 :
247 : /// @brief information whether an output occurred at all
248 : bool myWasInformed;
249 :
250 : /// @brief do not output more messages of the same type if the count exceeds this threshold
251 : int myAggregationThreshold;
252 :
253 : /// @brief count for messages of the same type
254 : std::map<const std::string, int> myAggregationCount;
255 :
256 : /// @brief The list of retrievers that shall be informed about new messages or errors
257 : std::vector<OutputDevice*> myRetrievers;
258 :
259 : /// @brief storage for initial messages
260 : std::vector<std::string> myInitialMessages;
261 :
262 : /** @brief Flag to enable or disable debug output
263 : *
264 : * This value is used to show more internal information through warning messages about certain operations
265 : */
266 : static bool myWriteDebugMessages;
267 :
268 : /// @brief Flag to enable or disable GL specific debug output
269 : static bool myWriteDebugGLMessages;
270 :
271 : /// @brief Whether to prefix every message with a time stamp
272 : static bool myWriteTimestamps;
273 :
274 : /// @brief Whether to prefix every message with the process id
275 : static bool myWriteProcessId;
276 :
277 : /// @brief The possibly translated error prefix (mainly for speedup)
278 : static std::string myErrorPrefix;
279 :
280 : /// @brief The possibly translated warning prefix (mainly for speedup)
281 : static std::string myWarningPrefix;
282 :
283 : private:
284 : /// @brief invalid copy constructor
285 : MsgHandler(const MsgHandler& s) = delete;
286 :
287 : /// @brief invalid assignment operator
288 : MsgHandler& operator=(const MsgHandler& s) = delete;
289 : };
290 :
291 :
292 : // ===========================================================================
293 : // global definitions
294 : // ===========================================================================
295 : #define WRITE_WARNING(msg) MsgHandler::getWarningInstance()->inform(msg);
296 : #define WRITE_WARNINGF(...) MsgHandler::getWarningInstance()->informf(__VA_ARGS__);
297 : #define WRITE_MESSAGE(msg) MsgHandler::getMessageInstance()->inform(msg);
298 : #define WRITE_MESSAGEF(...) MsgHandler::getMessageInstance()->informf(__VA_ARGS__);
299 : #define PROGRESS_BEGIN_MESSAGE(msg) MsgHandler::getMessageInstance()->beginProcessMsg((msg) + std::string(" ..."));
300 : #define PROGRESS_DONE_MESSAGE() MsgHandler::getMessageInstance()->endProcessMsg2(true);
301 : #define PROGRESS_BEGIN_TIME_MESSAGE(msg) SysUtils::getCurrentMillis(); MsgHandler::getMessageInstance()->beginProcessMsg((msg) + std::string(" ..."));
302 : #define PROGRESS_TIME_MESSAGE(before) MsgHandler::getMessageInstance()->endProcessMsg2(true, SysUtils::getCurrentMillis() - before);
303 : #define PROGRESS_FAILED_MESSAGE() MsgHandler::getMessageInstance()->endProcessMsg2(false);
304 : #define WRITE_ERROR(msg) MsgHandler::getErrorInstance()->inform(msg);
305 : #define WRITE_ERRORF(...) MsgHandler::getErrorInstance()->informf(__VA_ARGS__);
306 : #define WRITE_DEBUG(msg) if(MsgHandler::writeDebugMessages()){MsgHandler::getDebugInstance()->inform(msg);};
307 : #define WRITE_GLDEBUG(msg) if(MsgHandler::writeDebugGLMessages()){MsgHandler::getGLDebugInstance()->inform(msg);};
308 : #ifdef HAVE_INTL
309 : // basic translation
310 : #define TL(string) gettext(string)
311 : // complex translation ("This % an %", "is", "example")
312 : #define TLF(string, ...) StringUtils::format(gettext(string), __VA_ARGS__)
313 : #else
314 : // basic translation
315 : #define TL(string) (string)
316 : // complex translation ("This % an %", "is", "example")
317 : #define TLF(string, ...) StringUtils::format(string, __VA_ARGS__)
318 : #endif
|