/* Copyright (c) 2012 Boris Moiseev (cyberbobs at gmail dot com) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation and appearing in the file LICENSE.LGPL included in the packaging of this file. This program 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. */ // Local #include "Logger.h" #include "AbstractAppender.h" #include "AbstractStringAppender.h" // Qt #include #include #include #include #include #include #if defined(Q_OS_ANDROID) # include # include #endif // STL #include /** * \file Logger.h * \brief A file containing the description of Logger class and and additional useful macros for logging */ /** * \mainpage * * Logger is a simple way to write the history of your application lifecycle to any target logging device (which is * called Appender and may write to any target you will implement with it: console, text file, XML or something - you * choose) and to map logging message to a class, function, source file and line of code which it is called from. * * Some simple appenders (which may be considered an examples) are provided with the Logger itself: see ConsoleAppender * and FileAppender documentation. * * It supports using it in a multithreaded applications, so all of its functions are thread safe. * * Simple usage example: * \code * #include * * #include * #include * * int main(int argc, char* argv[]) * { * QCoreApplication app(argc, argv); * ... * ConsoleAppender* consoleAppender = new ConsoleAppender; * consoleAppender->setFormat("[%{type:-7}] <%{Function}> %{message}\n"); * cuteLogger->registerAppender(consoleAppender); * ... * LOG_INFO("Starting the application"); * int result = app.exec(); * ... * if (result) * LOG_WARNING() << "Something went wrong." << "Result code is" << result; * * return result; * } * \endcode * * Logger internally uses the lazy-initialized singleton object and needs no definite initialization, but you may * consider registering a log appender before calling any log recording functions or macros. * * The library design of Logger allows you to simply mass-replace all occurrences of qDebug and similar calls with * similar Logger macros (e.g. LOG_DEBUG()) * * \note Logger uses a singleton global instance which lives through all the application life cycle and self-destroys * destruction of the QCoreApplication (or QApplication) instance. It needs a QCoreApplication instance to be * created before any of the Logger's functions are called. * * \sa cuteLogger * \sa LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_FATAL * \sa LOG_CTRACE, LOG_CDEBUG, LOG_CINFO, LOG_CWARNING, LOG_CERROR, LOG_CFATAL * \sa LOG_ASSERT * \sa LOG_TRACE_TIME, LOG_DEBUG_TIME, LOG_INFO_TIME * \sa AbstractAppender */ /** * \def cuteLogger * * \brief Macro returning the current instance of Logger object * * If you haven't created a local Logger object it returns the same value as the Logger::globalInstance() functions. * This macro is a recommended way to get an access to the Logger instance used in current class. * * Example: * \code * ConsoleAppender* consoleAppender = new ConsoleAppender; * cuteLogger->registerAppender(consoleAppender); * \endcode * * \sa Logger::globalInstance() */ /** * \def LOG_TRACE * * \brief Writes the trace log record * * This macro is the convinient way to call Logger::write(). It uses the common preprocessor macros \c __FILE__, * \c __LINE__ and the standart Qt \c Q_FUNC_INFO macros to automatically determine the needed parameters to call * Logger::write(). * * \note This and other (LOG_INFO() etc...) macros uses the variadic macro arguments to give convinient usage form for * the different versions of Logger::write() (using the QString or const char* argument or returning the QDebug class * instance). Not all compilers will support this. Please, consider reviewing your compiler documentation to ensure * it support __VA_ARGS__ macro. * * \sa Logger::LogLevel * \sa Logger::write() */ /** * \def LOG_DEBUG * * \brief Writes the debug log record * * This macro records the debug log record using the Logger::write() function. It works similar to the LOG_TRACE() * macro. * * \sa LOG_TRACE() * \sa Logger::LogLevel * \sa Logger::write() */ /** * \def LOG_INFO * * \brief Writes the info log record * * This macro records the info log record using the Logger::write() function. It works similar to the LOG_TRACE() * macro. * * \sa LOG_TRACE() * \sa Logger::LogLevel * \sa Logger::write() */ /** * \def LOG_WARNING * * \brief Write the warning log record * * This macro records the warning log record using the Logger::write() function. It works similar to the LOG_TRACE() * macro. * * \sa LOG_TRACE() * \sa Logger::LogLevel * \sa Logger::write() */ /** * \def LOG_ERROR * * \brief Write the error log record * This macro records the error log record using the Logger::write() function. It works similar to the LOG_TRACE() * macro. * * \sa LOG_TRACE() * \sa Logger::LogLevel * \sa Logger::write() */ /** * \def LOG_FATAL * * \brief Write the fatal log record * * This macro records the fatal log record using the Logger::write() function. It works similar to the LOG_TRACE() * macro. * * \note Recording of the log record using the Logger::Fatal log level will lead to calling the STL abort() * function, which will interrupt the running of your software and begin the writing of the core dump. * * \sa LOG_TRACE() * \sa Logger::LogLevel * \sa Logger::write() */ /** * \def LOG_CTRACE(category) * * \brief Writes the trace log record to the specific category * * This macro is the similar to the LOG_TRACE() macro, but has a category parameter * to write only to the category appenders (registered using Logger::registerCategoryAppender() method). * * \param category category name string * * \sa LOG_TRACE() * \sa Logger::LogLevel * \sa Logger::registerCategoryAppender() * \sa Logger::write() * \sa LOG_CATEGORY(), LOG_GLOBAL_CATEGORY() */ /** * \def LOG_CDEBUG * * \brief Writes the debug log record to the specific category * * This macro records the debug log record using the Logger::write() function. It works similar to the LOG_CTRACE() * macro. * * \sa LOG_CTRACE() */ /** * \def LOG_CINFO * * \brief Writes the info log record to the specific category * * This macro records the info log record using the Logger::write() function. It works similar to the LOG_CTRACE() * macro. * * \sa LOG_CTRACE() */ /** * \def LOG_CWARNING * * \brief Writes the warning log record to the specific category * * This macro records the warning log record using the Logger::write() function. It works similar to the LOG_CTRACE() * macro. * * \sa LOG_CTRACE() */ /** * \def LOG_CERROR * * \brief Writes the error log record to the specific category * * This macro records the error log record using the Logger::write() function. It works similar to the LOG_CTRACE() * macro. * * \sa LOG_CTRACE() */ /** * \def LOG_CFATAL * * \brief Write the fatal log record to the specific category * * This macro records the fatal log record using the Logger::write() function. It works similar to the LOG_CTRACE() * macro. * * \note Recording of the log record using the Logger::Fatal log level will lead to calling the STL abort() * function, which will interrupt the running of your software and begin the writing of the core dump. * * \sa LOG_CTRACE() */ /** * \def LOG_CATEGORY(category) * * \brief Create logger instance inside your custom class to log all messages to the specified category * * This macro is used to pass all log messages inside your custom class to the specific category. * You must include this macro inside your class declaration (similarly to the Q_OBJECT macro). * Internally, this macro redefines cuteLoggerInstance() function, creates the local Logger object inside your class and * sets the default category to the specified parameter. * * Thus, any call to cuteLoggerInstance() (for example, inside LOG_TRACE() macro) will return the local Logger object, * so any logging message will be directed to the default category. * * \note This macro does not register any appender to the newly created logger instance. You should register * logger appenders manually, inside your class. * * Usage example: * \code * class CustomClass : public QObject * { * Q_OBJECT * LOG_CATEGORY("custom_category") * ... * }; * * CustomClass::CustomClass(QObject* parent) : QObject(parent) * { * cuteLogger->registerAppender(new FileAppender("custom_category_log")); * LOG_TRACE() << "Trace to the custom category log"; * } * \endcode * * If used compiler supports C++11 standard, LOG_CATEGORY and LOG_GLOBAL_CATEGORY macros would also work when added * inside of any scope. It could be useful, for example, to log every single run of a method to a different file. * * \code * void foo() * { * QString categoryName = QDateTime::currentDateTime().toString("yyyy-MM-ddThh-mm-ss-zzz"); * LOG_CATEGORY(categoryName); * cuteLogger->registerAppender(new FileAppender(categoryName + ".log")); * ... * } * \endcode * * \sa Logger::write() * \sa LOG_TRACE * \sa Logger::registerCategoryAppender() * \sa Logger::setDefaultCategory() * \sa LOG_GLOBAL_CATEGORY */ /** * \def LOG_GLOBAL_CATEGORY(category) * * \brief Create logger instance inside your custom class to log all messages both to the specified category and to * the global logger instance. * * This macro is similar to LOG_CATEGORY(), but also passes all log messages to the global logger instance appenders. * It is equal to defining the local category logger using LOG_CATEGORY macro and calling: * \code cuteLogger->logToGlobalInstance(cuteLogger->defaultCategory(), true); \endcode * * \sa LOG_CATEGORY * \sa Logger::logToGlobalInstance() * \sa Logger::defaultCategory() * \sa Logger::registerCategoryAppender() * \sa Logger::write() */ /** * \def LOG_ASSERT * * \brief Check the assertion * * This macro is a convinient and recommended to use way to call Logger::writeAssert() function. It uses the * preprocessor macros (as the LOG_DEBUG() does) to fill the necessary arguments of the Logger::writeAssert() call. It * also uses undocumented but rather mature and stable \c qt_noop() function (which does nothing) when the assertion * is true. * * Example: * \code * bool b = checkSomething(); * ... * LOG_ASSERT(b == true); * \endcode * * \sa Logger::writeAssert() */ /** * \def LOG_TRACE_TIME * * \brief Logs the processing time of current function / code block * * This macro automagically measures the function or code of block execution time and outputs it as a Logger::Trace * level log record. * * Example: * \code * int foo() * { * LOG_TRACE_TIME(); * ... // Do some long operations * return 0; * } // Outputs: Function foo finished in