Line data Source code
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 12414 : cleanupOnEnd();
67 12414 : myFactory = func;
68 4373 : }
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 31580 : 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 542889 : void informf(const std::string& format, T value, Targs... Fargs) {
117 542889 : if (!aggregationThresholdReached(format)) {
118 1372409 : inform(StringUtils::format(format, value, Fargs...), true);
119 : }
120 542889 : }
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 91600 : myAggregationThreshold = thresh;
166 : }
167 :
168 : int getAggregationThreshold() const {
169 0 : 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 5738385 : inline std::string build(const std::string& msg, bool addType) {
178 : std::string prefix;
179 5738385 : if (myWriteTimestamps) {
180 12 : prefix += "[" + StringUtils::isoTimeString() + "] ";
181 : }
182 5738385 : if (myWriteProcessId) {
183 12 : prefix += buildProcessIdPrefix();
184 : }
185 5738385 : if (addType) {
186 5733672 : 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 5738385 : return prefix + msg;
206 : }
207 :
208 542889 : virtual bool aggregationThresholdReached(const std::string& format) {
209 542889 : 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
|