/* * utilite is a cross-platform library with * useful utilities for fast and small developing. * Copyright (C) 2010 Mathieu Labbe * * utilite is free library: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * utilite is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef ULOGGER_H #define ULOGGER_H #include "find_object/FindObjectExp.h" // DLL export/import defines #include "find_object/utilite/UMutex.h" #include "find_object/utilite/UDestroyer.h" #include #include #include #include #include #if _MSC_VER #undef min #undef max #endif /** * \file ULogger.h * \brief ULogger class and convenient macros * * This contains macros useful for logging a message anywhere in the * application. Once the ULogger is set, use these macros like a printf to * print debug messages. */ /* * Convenient macros for logging... */ #define ULOGGER_LOG(level, ...) ULogger::write(level, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) #define ULOGGER_DEBUG(...) ULOGGER_LOG(ULogger::kDebug, __VA_ARGS__) #define ULOGGER_INFO(...) ULOGGER_LOG(ULogger::kInfo, __VA_ARGS__) #define ULOGGER_WARN(...) ULOGGER_LOG(ULogger::kWarning, __VA_ARGS__) #define ULOGGER_ERROR(...) ULOGGER_LOG(ULogger::kError, __VA_ARGS__) #define ULOGGER_FATAL(...) ULOGGER_LOG(ULogger::kFatal, __VA_ARGS__) #define UDEBUG(...) ULOGGER_DEBUG(__VA_ARGS__) #define UINFO(...) ULOGGER_INFO(__VA_ARGS__) #define UWARN(...) ULOGGER_WARN(__VA_ARGS__) #define UERROR(...) ULOGGER_ERROR(__VA_ARGS__) #define UFATAL(...) ULOGGER_FATAL(__VA_ARGS__) #define UASSERT(condition) if(!(condition)) ULogger::write(ULogger::kFatal, __FILE__, __LINE__, __FUNCTION__, "Condition (%s) not met!", #condition) #define UASSERT_MSG(condition, msg_str) if(!(condition)) ULogger::write(ULogger::kFatal, __FILE__, __LINE__, __FUNCTION__, "Condition (%s) not met! [%s]", #condition, msg_str) /** * \def UDEBUG(...) * Print a debug level message in the logger. Format is the same as a printf: * @code * UDEBUG("This is a debug message with the number %d", 42); * @endcode */ /** * \def UINFO(...) * Print a information level message in the logger. Format is the same as a printf: * @code * UINFO("This is a information message with the number %d", 42); * @endcode */ /** * \def UWARN(...) * Print a warning level message in the logger. Format is the same as a printf: * @code * UWARN("This is a warning message with the number %d", 42); * @endcode */ /** * \def UERROR(...) * Print an error level message in the logger. Format is the same as a printf: * @code * UERROR("This is an error message with the number %d", 42); * @endcode */ /** * \def UFATAL(...) * Print a fatal error level message in the logger. The application will exit on * fatal error. Format is the same as a printf: * @code * UFATAL("This is a fatal error message with the number %d", 42); * @endcode */ /** * \def UASSERT(condition, ...) * Print a fatal error level message in the logger if condition is not met. The application will exit on * fatal error. Format is the same as a printf: * @code * UASSERT(a!=42, "This is a fatal error message with the number %d", 42); * @endcode */ /** * This class is used to log messages with time on a console, in a file * and/or with an event. At the start of the application, call * ULogger::setType() with the type of the logger you want (see ULogger::Type, the type of the output * can be changed at the run-time.). To use it, * simply call the convenient macros UDEBUG(), UINFO(), UWARN(), UERROR(), UFATAL() depending of * the severity of the message. You can disable some messages by setting the logger * level ULogger::setLevel() to severity you want, defined by ULogger::Level. A fatal message * will make the application to exit, printing the message on console (whatever the logger type) and * posting a ULogEvent (synchronously... see UEventsManager::post()) before exiting. * * The display of the logged messages can be modified: * - If you don't want the level label, set ULogger::setPrintLevel() to false. * - If you don't want the time label, set ULogger::setPrintTime() to false. * - If you don't want the end of line added, set ULogger::setPrintEndline() to false. * - If you don't the full path of the message, set ULogger::setPrintWhereFullPath() to false. * - If you don't the path of the message, set ULogger::setPrintWhere() to false. * * When using a file logger (kTypeLogger), it can be useful in some * application to buffer messages before writing them to hard drive (avoiding * hard drive latencies). You can set ULogger::setBuffered() to true to do that. When the * buffered messages will be written to file on appllciation exit (ULogger destructor) or when * ULogger::flush() is called. * * If you want the application to exit on a lower severity level than kFatal, * you can set ULogger::setExitLevel() to any ULogger::Type you want. * * Example: * @code * #include * int main(int argc, char * argv[]) * { * // Set the logger type. The choices are kTypeConsole, * // kTypeFile or kTypeNoLog (nothing is logged). * ULogger::setType(ULogger::kTypeConsole); * * // Set the logger severity level (kDebug, kInfo, kWarning, kError, kFatal). * // All log entries under the severity level are not logged. Here, * // only debug messages are not logged. * ULogger::setLevel(ULogger::kInfo); * * // Use a predefined Macro to easy logging. It can be * // called anywhere in the application as the logger is * // a Singleton. * UDEBUG("This message won't be logged because the " * "severity level of the logger is set to kInfo."); * * UINFO("This message is logged."); * * UWARN("A warning message..."); * * UERROR("An error message with code %d.", 42); * * return 0; * } * @endcode * Output: * @code * [ INFO] (2010-09-25 18:08:20) main.cpp:18::main() This message is logged. * [ WARN] (2010-09-25 18:08:20) main.cpp:20::main() A warning message... * [ERROR] (2010-09-25 18:08:20) main.cpp:22::main() An error message with code 42. * @endcode * * Another useful form of the ULogger is to use it with the UTimer class. Here an example: * @code * #include * #include * ... * UTimer timer; // automatically starts * // do some works for part A * UINFO("Time for part A = %f s", timer.ticks()); * // do some works for part B * UINFO("Time for part B = %f s", timer.ticks()); * // do some works for part C * UINFO("Time for part C = %f s", timer.ticks()); * ... * @endcode * * @see setType() * @see setLevel() * @see UDEBUG(), UINFO(), UWARN(), UERROR(), UFATAL() * */ class FINDOBJECT_EXP ULogger { public: /** * The default log file name. */ static const std::string kDefaultLogFileName; /** * Loggers available: * @code * kTypeNoLog, kTypeConsole, kTypeFile * @endcode */ enum Type{kTypeNoLog, kTypeConsole, kTypeFile}; /** * Logger levels, from lowest severity to highest: * @code * kDebug, kInfo, kWarning, kError, kFatal * @endcode */ enum Level{kDebug, kInfo, kWarning, kError, kFatal}; /** * Set the type of the logger. When using kTypeFile, the parameter "fileName" would be * changed (default is "./ULog.txt"), and optionally "append" if we want the * logger to append messages to file or to overwrite the file. * @param type the ULogger::Type of the logger. * @param fileName file name used with a file logger type. * @param append if true, the file isn't overwritten, otherwise it is. * * TODO : Can it be useful to have 2 or more types at the same time ? Print * in console and file at the same time. */ static void setType(Type type, const std::string &fileName = kDefaultLogFileName, bool append = true); static Type type() {return type_;} // Setters /** * Print time: default true. * @param printTime true to print time, otherwise set to false. */ static void setPrintTime(bool printTime) {printTime_ = printTime;} static bool isPrintTime() {return printTime_;} /** * Print level: default true. * @param printLevel true to print level, otherwise set to false. */ static void setPrintLevel(bool printLevel) {printLevel_ = printLevel;} static bool isPrintLevel() {return printLevel_;} /** * Print end of line: default true. * @param printLevel true to print end of line, otherwise set to false. */ static void setPrintEndline(bool printEndline) {printEndline_ = printEndline;} static bool isPrintEndLine() {return printEndline_;} /** * Print text with color: default true. * Dark green for Debug, white for Info, yellow for Warning, red for Error and Fatal. * @param printColored true to print text with color, otherwise set to false. */ static void setPrintColored(bool printColored) {printColored_ = printColored;} static bool isPrintColored() {return printColored_;} /** * Print where is this message in source code: default true. * @param printWhere true to print where, otherwise set to false. */ static void setPrintWhere(bool printWhere) {printWhere_ = printWhere;} static bool isPrintWhere() {return printWhere_;} /** * Print the full path: default true. ULogger::setPrintWhere() must be true to have path printed. * @param printWhereFullPath true to print the full path, otherwise set to false. */ static void setPrintWhereFullPath(bool printWhereFullPath) {printWhereFullPath_ = printWhereFullPath;} static bool isPrintWhereFullPath() {return printWhereFullPath_;} /** * Set is the logger buffers messages, default false. When true, the messages are * buffered until the application is closed or ULogger::flush() is called. * @see ULogger::flush() * @param buffered true to buffer messages, otherwise set to false. */ static void setBuffered(bool buffered); static bool isBuffered() {return buffered_;} /** * Set logger level: default kInfo. All messages over the severity set * are printed, other are ignored. The severity is from the lowest to * highest: * - kDebug * - kInfo * - kWarning * - kError * - kFatal * @param level the minimum level of the messages printed. */ static void setLevel(ULogger::Level level) {level_ = level;} static ULogger::Level level() {return level_;} /** * Make application to exit when a log with level is written (useful for debugging). The message is printed to * console (whatever the logger type) and an ULogEvent is sent (synchronously... see UEventsManager::post()) before exiting. * * Note : A kFatal level will always exit whatever the level specified here. */ static void setExitLevel(ULogger::Level exitLevel) {exitLevel_ = exitLevel;} static ULogger::Level exitLevel() {return exitLevel_;} /** * An ULogEvent is sent on each message logged at the specified level. * Note : On message with level >= exitLevel, the event is sent synchronously (see UEventsManager::post()). * @see ULogEvent * @see setExitLevel() */ static void setEventLevel(ULogger::Level eventSentLevel) {eventLevel_ = eventSentLevel;} static ULogger::Level eventLevel() {return eventLevel_;} /** * Reset to default parameters. */ static void reset(); /** * Flush buffered messages. * @see setBuffered() */ static void flush(); /** * Write a message directly to logger without level handling. * @param msg the message to write. * @param ... the variable arguments * @deprecated use UDEBUG(), UINFO(), UWARN(), UERROR() or UFATAL() */ static void write(const char* msg, ...); /* * Write a message to logger: use UDEBUG(), UINFO(), UWARN(), UERROR() or UFATAL() instead. * @param level the log level of this message * @param file the file path * @param line the line in the file * @param function the function name in which the message is logged * @param msg the message to write * @param ... the variable arguments */ static void write(ULogger::Level level, const char * file, int line, const char *function, const char* msg, ...); /** * Get the time in the format "2008-7-13 12:23:44". * @param timeStr string were the time will be copied. * @return the number of characters written, or 0 if an error occurred. */ static int getTime(std::string &timeStr); protected: /* * This method is used to have a reference on the * Logger. When no Logger exists, one is * created. There is only one instance in the application. * Must be protected by loggerMutex_. * See the Singleton pattern for further explanation. * * @return the reference on the Logger */ static ULogger* getInstance(); /* * Called only once in getInstance(). It can't be instanciated * by the user. * * @see getInstance() */ ULogger() {} /* * Only called by a Destroyer. * @see Destroyer */ virtual ~ULogger(); /* * Flush buffered messages */ void _flush(); /* * A Destroyer is used to remove a dynamicaly created * Singleton. It is friend here to have access to the * destructor. * * @see Destroyer */ friend class UDestroyer; /* * The log file name. */ static std::string logFileName_; /* * Default true, it doesn't overwrite the file. */ static bool append_; private: /* * Create an instance according to type. See the Abstract factory * pattern for further explanation. * @see type_ * @return the reference on the new logger */ static ULogger* createInstance(); /* * Write a message on the output with the format : * "A message". Inherited class * must override this method to output the message. It * does nothing by default. * @param msg the message to write. * @param arg the variable arguments */ virtual void _write(const char* msg, va_list arg) {} // Do nothing by default virtual void _writeStr(const char* msg) {} // Do nothing by default private: /* * The Logger instance pointer. */ static ULogger* instance_; /* * The Logger's destroyer */ static UDestroyer destroyer_; /* * If the logger prints the time for each message. * Default is true. */ static bool printTime_; /* * If the logger prints the level for each message. * Default is true. */ static bool printLevel_; /* * If the logger prints the end line for each message. * Default is true. */ static bool printEndline_; /* * If the logger prints text with color. * Default is true. */ static bool printColored_; /* * If the logger prints where the message is logged (fileName::function():line). * Default is true. */ static bool printWhere_; /* * If the logger prints the full path of the source file * where the message is written. Only works when * "printWhere_" is true. * Default is false. */ static bool printWhereFullPath_; /* * If the logger limit the size of the "where" path to * characters. If the path is over 8 characters, a "~" * is added. Only works when "printWhereFullPath_" is false. * Default is false. */ static bool limitWhereLength_; /* * The type of the logger. */ static Type type_; /* * The severity of the log. */ static Level level_; /* * The severity at which the application exits. * Note : A FATAL level will always exit whatever the level specified here. */ static Level exitLevel_; /* * The severity at which the message is also sent in a ULogEvent. */ static Level eventLevel_; static const char * levelName_[5]; /* * Mutex used when accessing public functions. */ static UMutex loggerMutex_; /* * If the logger prints messages only when ULogger::flush() is called. * Default is false. */ static bool buffered_; static std::string bufferedMsgs_; /* * State attribute. This state happens when an exit level * message is received. * Messages received during this state are not logged. * @see exitLevel_ */ static bool exitingState_; }; #endif // ULOGGER_H