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 11119 : cleanupOnEnd(); 67 11119 : myFactory = func; 68 3850 : } 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 1428 : return myWriteDebugMessages; 94 : } 95 : 96 : /// @brief check whether to enable/disable gl-debug messages 97 : static inline bool writeDebugGLMessages() { 98 61011 : 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 374197 : void informf(const std::string& format, T value, Targs... Fargs) { 123 374197 : if (!aggregationThresholdReached(format)) { 124 1017230 : inform(StringUtils::format(format, value, Fargs...), true); 125 : } 126 374197 : } 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 1338876 : inline std::string build(const std::string& msg, bool addType) { 177 : std::string prefix; 178 1338876 : if (myWriteTimestamps) { 179 10 : prefix += buildTimestampPrefix(); 180 : } 181 1338876 : if (myWriteProcessId) { 182 10 : prefix += buildProcessIdPrefix(); 183 : } 184 1338876 : if (addType) { 185 1333121 : 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 2677752 : return prefix + msg; 205 : } 206 : 207 374196 : virtual bool aggregationThresholdReached(const std::string& format) { 208 374196 : return myAggregationThreshold >= 0 && myAggregationCount[format]++ >= myAggregationThreshold; 209 : } 210 : 211 : void setAggregationThreshold(const int thresh) { 212 86300 : 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