summaryrefslogtreecommitdiffstats
path: root/rbutil/rbutilqt
diff options
context:
space:
mode:
Diffstat (limited to 'rbutil/rbutilqt')
-rw-r--r--rbutil/rbutilqt/logger/AbstractAppender.cpp58
-rw-r--r--rbutil/rbutilqt/logger/AbstractAppender.h125
-rw-r--r--rbutil/rbutilqt/logger/AbstractStringAppender.cpp161
-rw-r--r--rbutil/rbutilqt/logger/AbstractStringAppender.h116
-rw-r--r--rbutil/rbutilqt/logger/ConsoleAppender.cpp25
-rw-r--r--rbutil/rbutilqt/logger/Logger.cpp370
-rw-r--r--rbutil/rbutilqt/logger/Logger.h319
-rw-r--r--rbutil/rbutilqt/logger/README.ROCKBOX6
-rw-r--r--rbutil/rbutilqt/logger/include/AbstractAppender.h49
-rw-r--r--rbutil/rbutilqt/logger/include/AbstractStringAppender.h46
-rw-r--r--rbutil/rbutilqt/logger/include/ConsoleAppender.h (renamed from rbutil/rbutilqt/logger/ConsoleAppender.h)18
-rw-r--r--rbutil/rbutilqt/logger/include/CuteLogger_global.h (renamed from rbutil/rbutilqt/logger/CuteLogger_global.h)0
-rw-r--r--rbutil/rbutilqt/logger/include/FileAppender.h (renamed from rbutil/rbutilqt/logger/FileAppender.h)20
-rw-r--r--rbutil/rbutilqt/logger/include/Logger.h237
-rw-r--r--rbutil/rbutilqt/logger/include/OutputDebugAppender.h (renamed from rbutil/rbutilqt/logger/OutputDebugAppender.h)8
-rw-r--r--rbutil/rbutilqt/logger/logger.pri29
-rw-r--r--rbutil/rbutilqt/logger/src/AbstractAppender.cpp147
-rw-r--r--rbutil/rbutilqt/logger/src/AbstractStringAppender.cpp459
-rw-r--r--rbutil/rbutilqt/logger/src/ConsoleAppender.cpp64
-rw-r--r--rbutil/rbutilqt/logger/src/FileAppender.cpp (renamed from rbutil/rbutilqt/logger/FileAppender.cpp)59
-rw-r--r--rbutil/rbutilqt/logger/src/Logger.cpp1099
-rw-r--r--rbutil/rbutilqt/logger/src/OutputDebugAppender.cpp (renamed from rbutil/rbutilqt/logger/OutputDebugAppender.cpp)14
-rw-r--r--rbutil/rbutilqt/main.cpp8
-rw-r--r--rbutil/rbutilqt/systrace.cpp6
24 files changed, 2201 insertions, 1242 deletions
diff --git a/rbutil/rbutilqt/logger/AbstractAppender.cpp b/rbutil/rbutilqt/logger/AbstractAppender.cpp
deleted file mode 100644
index de86b930d0..0000000000
--- a/rbutil/rbutilqt/logger/AbstractAppender.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- Copyright (c) 2010 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 "AbstractAppender.h"
-
-// Qt
-#include <QMutexLocker>
-
-
-AbstractAppender::AbstractAppender()
- : m_detailsLevel(Logger::Debug)
-{}
-
-
-AbstractAppender::~AbstractAppender()
-{}
-
-
-Logger::LogLevel AbstractAppender::detailsLevel() const
-{
- QMutexLocker locker(&m_detailsLevelMutex);
- return m_detailsLevel;
-}
-
-
-void AbstractAppender::setDetailsLevel(Logger::LogLevel level)
-{
- QMutexLocker locker(&m_detailsLevelMutex);
- m_detailsLevel = level;
-}
-
-
-void AbstractAppender::setDetailsLevel(const QString& level)
-{
- setDetailsLevel(Logger::levelFromString(level));
-}
-
-
-void AbstractAppender::write(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
- const char* function, const QString& message)
-{
- if (logLevel >= detailsLevel())
- {
- QMutexLocker locker(&m_writeMutex);
- append(timeStamp, logLevel, file, line, function, message);
- }
-}
diff --git a/rbutil/rbutilqt/logger/AbstractAppender.h b/rbutil/rbutilqt/logger/AbstractAppender.h
deleted file mode 100644
index df1df4957c..0000000000
--- a/rbutil/rbutilqt/logger/AbstractAppender.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- Copyright (c) 2010 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.
-*/
-#ifndef ABSTRACTAPPENDER_H
-#define ABSTRACTAPPENDER_H
-
-// Local
-#include "CuteLogger_global.h"
-#include <Logger.h>
-
-// Qt
-#include <QMutex>
-
-//! The AbstractAppender class provides an abstract base class for writing a log entries.
-/**
- * The AbstractAppender class is the base interface class for all log appenders that could be used with Logger.
- *
- * AbstractAppender provides a common implementation for the thread safe, mutex-protected logging of application
- * messages, such as ConsoleAppender, FileAppender or something else. AbstractAppender is abstract and can not be
- * instantiated, but you can use any of its subclasses or create a custom log appender at your choice.
- *
- * Appenders are the logical devices that is aimed to be attached to Logger object by calling
- * Logger::registerAppender(). On each log record call from the application Logger object sequentially calls write()
- * function on all the appenders registered in it.
- *
- * You can subclass AbstractAppender to implement a logging target of any kind you like. It may be the external logging
- * subsystem (for example, syslog in *nix), XML file, SQL database entries, D-Bus messages or anything else you can
- * imagine.
- *
- * For the simple non-structured plain text logging (for example, to a plain text file or to the console output) you may
- * like to subclass the AbstractStringAppender instead of AbstractAppender, which will give you a more convinient way to
- * control the format of the log output.
- *
- * \sa AbstractStringAppender
- * \sa Logger::registerAppender()
- */
-class CUTELOGGERSHARED_EXPORT AbstractAppender
-{
- public:
- //! Constructs a AbstractAppender object.
- AbstractAppender();
-
- //! Destructs the AbstractAppender object.
- virtual ~AbstractAppender();
-
- //! Returns the current details level of appender.
- /**
- * Log records with a log level lower than a current detailsLevel() will be silently ignored by appender and would not
- * be sent to its append() function.
- *
- * It provides additional logging flexibility, allowing you to set the different severity levels for different types
- * of logs.
- *
- * \note This function is thread safe.
- *
- * \sa setDetailsLevel()
- * \sa Logger::LogLevel
- */
- Logger::LogLevel detailsLevel() const;
-
- //! Sets the current details level of appender.
- /**
- * \note This function is thread safe.
- *
- * \sa detalsLevel()
- * \sa Logger::LogLevel
- */
- void setDetailsLevel(Logger::LogLevel level);
-
- //! Sets the current details level of appender
- /**
- * This function is provided for convinience, it behaves like an above function.
- *
- * \sa detalsLevel()
- * \sa Logger::LogLevel
- */
- void setDetailsLevel(const QString& level);
-
- //! Tries to write the log record to this logger
- /**
- * This is the function called by Logger object to write a log message to the appender.
- *
- * \note This function is thread safe.
- *
- * \sa Logger::write()
- * \sa detailsLevel()
- */
- void write(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, const char* function,
- const QString& message);
-
- protected:
- //! Writes the log record to the logger instance
- /**
- * This function is called every time when user tries to write a message to this AbstractAppender instance using
- * the write() function. Write function works as proxy and transfers only the messages with log level more or equal
- * to the current logLevel().
- *
- * Overload this function when you are implementing a custom appender.
- *
- * \note This function is not needed to be thread safe because it is never called directly by Logger object. The
- * write() function works as a proxy and protects this function from concurrent access.
- *
- * \sa Logger::write()
- */
- virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
- const char* function, const QString& message) = 0;
-
- private:
- QMutex m_writeMutex;
-
- Logger::LogLevel m_detailsLevel;
- mutable QMutex m_detailsLevelMutex;
-};
-
-#endif // ABSTRACTAPPENDER_H
diff --git a/rbutil/rbutilqt/logger/AbstractStringAppender.cpp b/rbutil/rbutilqt/logger/AbstractStringAppender.cpp
deleted file mode 100644
index 073ecb7782..0000000000
--- a/rbutil/rbutilqt/logger/AbstractStringAppender.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- Copyright (c) 2010 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 "AbstractStringAppender.h"
-
-// Qt
-#include <QReadLocker>
-#include <QWriteLocker>
-#include <QDateTime>
-#include <QRegExp>
-
-const char formattingMarker = '%';
-
-AbstractStringAppender::AbstractStringAppender()
- : m_format(QLatin1String("%t{yyyy-MM-ddTHH:mm:ss.zzz} [%-7l] <%c> %m\n"))
-{}
-
-
-QString AbstractStringAppender::format() const
-{
- QReadLocker locker(&m_formatLock);
- return m_format;
-}
-
-
-void AbstractStringAppender::setFormat(const QString& format)
-{
- QWriteLocker locker(&m_formatLock);
- m_format = format;
-}
-
-
-QString AbstractStringAppender::stripFunctionName(const char* name)
-{
- QRegExp rx("^.+\\s((?:[\\w\\d]+::)+)?([\\w\\d\\<\\>~]+)(?:\\(.*\\)).*$"); // XXX: SLOW!
- return QString::fromLatin1(name).replace(rx, QString(QLatin1String("\\1\\2")));
-}
-
-
-QString AbstractStringAppender::formattedString(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file,
- int line, const char* function, const QString& message) const
-{
- QString f = format();
- const int size = f.size();
-
- QString result;
-
- int i = 0;
- while (i < f.size())
- {
- QChar c = f.at(i);
-
- // We will silently ignore the broken % marker at the end of string
- if (c != QLatin1Char(formattingMarker) || (i + 1) == size)
- {
- result.append(c);
- }
- else
- {
- QChar command = f.at(++i);
-
- // Check for the padding instruction
- int fieldWidth = 0;
- if (command.isDigit() || command.category() == QChar::Punctuation_Dash)
- {
- int j = 1;
- while ((i + j) < size && f.at(i + j).isDigit())
- j++;
- fieldWidth = f.mid(i, j).toInt();
-
- i += j;
- command = f.at(i);
- }
-
- // Log record chunk to insert instead of formatting instruction
- QString chunk;
-
- // Time stamp
- if (command == QLatin1Char('t'))
- {
- if (f.at(i + 1) == QLatin1Char('{'))
- {
- int j = 1;
- while ((i + 2 + j) < size && f.at(i + 2 + j) != QLatin1Char('}'))
- j++;
-
- if ((i + 2 + j) < size)
- {
- chunk = timeStamp.toString(f.mid(i + 2, j));
-
- i += j;
- i += 2;
- }
- }
-
- if (chunk.isNull())
- chunk = timeStamp.toString(QLatin1String("HH:mm:ss.zzz"));
- }
-
- // Log level
- else if (command == QLatin1Char('l'))
- chunk = Logger::levelToString(logLevel);
-
- // Uppercased log level
- else if (command == QLatin1Char('L'))
- chunk = Logger::levelToString(logLevel).toUpper();
-
- // Filename
- else if (command == QLatin1Char('F'))
- chunk = QLatin1String(file);
-
- // Filename without a path
- else if (command == QLatin1Char('f'))
- chunk = QString(QLatin1String(file)).section('/', -1);
-
- // Source line number
- else if (command == QLatin1Char('i'))
- chunk = QString::number(line);
-
- // Function name, as returned by Q_FUNC_INFO
- else if (command == QLatin1Char('C'))
- chunk = QString::fromLatin1(function);
-
- // Stripped function name
- else if (command == QLatin1Char('c'))
- chunk = stripFunctionName(function);
-
- // Log message
- else if (command == QLatin1Char('m'))
- chunk = message;
-
- // We simply replace the double formatting marker (%) with one
- else if (command == QLatin1Char(formattingMarker))
- chunk = QLatin1Char(formattingMarker);
-
- // Do not process any unknown commands
- else
- {
- chunk = QLatin1Char(formattingMarker);
- chunk.append(command);
- }
-
- result.append(QString(QLatin1String("%1")).arg(chunk, fieldWidth));
- }
-
- ++i;
- }
-
- return result;
-}
diff --git a/rbutil/rbutilqt/logger/AbstractStringAppender.h b/rbutil/rbutilqt/logger/AbstractStringAppender.h
deleted file mode 100644
index 3cef63bff9..0000000000
--- a/rbutil/rbutilqt/logger/AbstractStringAppender.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- Copyright (c) 2010 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.
-*/
-#ifndef ABSTRACTSTRINGAPPENDER_H
-#define ABSTRACTSTRINGAPPENDER_H
-
-// Local
-#include "CuteLogger_global.h"
-#include <AbstractAppender.h>
-
-// Qt
-#include <QReadWriteLock>
-
-
-//! The AbstractStringAppender class provides a convinient base for appenders working with plain text formatted logs.
-/**
- * AbstractSringAppender is the simple extension of the AbstractAppender class providing the convinient way to create
- * custom log appenders working with a plain text formatted log targets.
- *
- * It have the formattedString() protected function that formats the logging arguments according to a format set with
- * setFormat().
- *
- * This class can not be directly instantiated because it contains pure virtual function inherited from AbstractAppender
- * class.
- *
- * For more detailed description of customizing the log output format see the documentation on the setFormat() function.
- */
-class CUTELOGGERSHARED_EXPORT AbstractStringAppender : public AbstractAppender
-{
- public:
- //! Constructs a new string appender object
- AbstractStringAppender();
-
- //! Returns the current log format string.
- /**
- * The default format is set to "%t{yyyy-MM-ddTHH:mm:ss.zzz} [%-7l] <%C> %m\n". You can set a different log record
- * format using the setFormat() function.
- *
- * \sa setFormat(const QString&)
- */
- QString format() const;
-
- //! Sets the logging format for writing strings to the log target with this appender.
- /**
- * The string format seems to be very common to those developers who have used a standart sprintf function.
- *
- * Log output format is a simple QString with the special markers (starting with % sign) which will be replaced with
- * it's internal meaning when writing a log record.
- *
- * Controlling marker begins with the percent sign (%) which is followed by (optional) field width argument, the
- * (necessary) single-letter command (which describes, what will be put to log record instead of marker, and an
- * additional formatting argument (in the {} brackets) supported for some of the log commands.
- *
- * Field width argument works almost identically to the \c QString::arg() \c fieldWidth argument (and uses it
- * internally). For example, \c "%-7l" will be replaced with the left padded debug level of the message
- * (\c "Debug ") or something. For the more detailed description of it you may consider to look to the Qt
- * Reference Documentation.
- *
- * Supported marker commands are:
- * \arg \c %t - timestamp. You may specify your custom timestamp format using the {} brackets after the marker,
- * timestamp format here will be similiar to those used in QDateTime::toString() function. For example,
- * "%t{dd-MM-yyyy, HH:mm}" may be replaced with "17-12-2010, 20:17" depending on current date and time.
- * The default format used here is "HH:mm:ss.zzz".
- * \arg \c %l - Log level. Possible log levels are shown in the Logger::LogLevel enumerator.
- * \arg \c %L - Uppercased log level.
- * \arg \c %F - Full source file name (with path) of the file that requested log recording. Uses the \c __FILE__
- * preprocessor macro.
- * \arg \c %f - Short file name (with stripped path).
- * \arg \c %i - Line number in the source file. Uses the \c __LINE__ preprocessor macro.
- * \arg \c %C - Name of function that called on of the LOG_* macros. Uses the \c Q_FUNC_INFO macro provided with
- * Qt.
- * \arg \c %c - [EXPERIMENTAL] Similiar to the %C, but the function name is stripped using stripFunctionName
- * \arg \c %m - The log message sent by the caller.
- * \arg \c %% - Convinient marker that is replaced with the single \c % mark.
- *
- * \note Format doesn't add \c '\\n' to the end of the format line. Please consider adding it manually.
- *
- * \sa format()
- * \sa stripFunctionName()
- * \sa Logger::LogLevel
- */
- void setFormat(const QString&);
-
- //! Strips the long function signature (as added by Q_FUNC_INFO macro)
- /**
- * The string processing drops the returning type, arguments and template parameters of function. It is definitely
- * useful for enchancing the log output readability.
- * \return stripped function name
- */
- static QString stripFunctionName(const char*);
-
- protected:
- //! Returns the string to record to the logging target, formatted according to the format().
- /**
- * \sa format()
- * \sa setFormat(const QString&)
- */
- QString formattedString(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
- const char* function, const QString& message) const;
-
- private:
- QString m_format;
- mutable QReadWriteLock m_formatLock;
-};
-
-#endif // ABSTRACTSTRINGAPPENDER_H
diff --git a/rbutil/rbutilqt/logger/ConsoleAppender.cpp b/rbutil/rbutilqt/logger/ConsoleAppender.cpp
deleted file mode 100644
index da4a43c740..0000000000
--- a/rbutil/rbutilqt/logger/ConsoleAppender.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- Copyright (c) 2010 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 "ConsoleAppender.h"
-
-// STL
-#include <iostream>
-
-
-void ConsoleAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
- const char* function, const QString& message)
-{
- std::cerr << qPrintable(formattedString(timeStamp, logLevel, file, line, function, message));
-}
diff --git a/rbutil/rbutilqt/logger/Logger.cpp b/rbutil/rbutilqt/logger/Logger.cpp
deleted file mode 100644
index 33ba50ec58..0000000000
--- a/rbutil/rbutilqt/logger/Logger.cpp
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- Copyright (c) 2010 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"
-
-// Qt
-#include <QCoreApplication>
-#include <QReadWriteLock>
-#include <QSemaphore>
-#include <QDateTime>
-#include <QIODevice>
-#include <QTextCodec>
-
-// STL
-#include <iostream>
-
-
-class LogDevice : public QIODevice
-{
- public:
- LogDevice()
- : m_semaphore(1)
- {}
-
- void lock(Logger::LogLevel logLevel, const char* file, int line, const char* function)
- {
- m_semaphore.acquire();
-
- if (!isOpen())
- open(QIODevice::WriteOnly);
-
- m_logLevel = logLevel;
- m_file = file;
- m_line = line;
- m_function = function;
- }
-
- protected:
- qint64 readData(char*, qint64)
- {
- return 0;
- }
-
- qint64 writeData(const char* data, qint64 maxSize)
- {
- if (maxSize > 0)
- Logger::write(m_logLevel, m_file, m_line, m_function, QString::fromLocal8Bit(QByteArray(data, maxSize)));
-
- m_semaphore.release();
- return maxSize;
- }
-
- private:
- QSemaphore m_semaphore;
- Logger::LogLevel m_logLevel;
- const char* m_file;
- int m_line;
- const char* m_function;
-};
-
-
-// Forward declarations
-static void cleanupLoggerPrivate();
-
-#if QT_VERSION >= 0x050000
-static void qtLoggerMessageHandler(QtMsgType, const QMessageLogContext& context, const QString& msg);
-#else
-static void qtLoggerMessageHandler(QtMsgType type, const char* msg);
-#endif
-
-/**
- * \internal
- *
- * LoggerPrivate class implements the Singleton pattern in a thread-safe way. It uses a static pointer to itself
- * protected by QReadWriteLock
- *
- * The appender list inside the LoggerPrivate class is also protected by QReadWriteLock so this class could be safely
- * used in a multi-threaded application.
- */
-class LoggerPrivate
-{
- public:
- static LoggerPrivate* m_self;
- static QReadWriteLock m_selfLock;
-
- static LoggerPrivate* instance()
- {
- LoggerPrivate* result = 0;
- {
- QReadLocker locker(&m_selfLock);
- result = m_self;
- }
-
- if (!result)
- {
- QWriteLocker locker(&m_selfLock);
- m_self = new LoggerPrivate;
-
-#if QT_VERSION >= 0x050000
- qInstallMessageHandler(qtLoggerMessageHandler);
-#else
- qInstallMsgHandler(qtLoggerMessageHandler);
-#endif
- qAddPostRoutine(cleanupLoggerPrivate);
- result = m_self;
- }
-
- return result;
- }
-
-
- LoggerPrivate()
- : m_logDevice(0)
- {}
-
-
- ~LoggerPrivate()
- {
- // Cleanup appenders
- QReadLocker appendersLocker(&m_appendersLock);
- foreach (AbstractAppender* appender, m_appenders)
- delete appender;
-
- // Cleanup device
- QReadLocker deviceLocker(&m_logDeviceLock);
- delete m_logDevice;
- }
-
-
- void registerAppender(AbstractAppender* appender)
- {
- QWriteLocker locker(&m_appendersLock);
-
- if (!m_appenders.contains(appender))
- m_appenders.append(appender);
- else
- std::cerr << "Trying to register appender that was already registered" << std::endl;
- }
-
-
- LogDevice* logDevice()
- {
- LogDevice* result = 0;
- {
- QReadLocker locker(&m_logDeviceLock);
- result = m_logDevice;
- }
-
- if (!result)
- {
- QWriteLocker locker(&m_logDeviceLock);
- m_logDevice = new LogDevice;
- result = m_logDevice;
- }
-
- return result;
- }
-
-
- void write(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, const char* function,
- const QString& message)
- {
- QReadLocker locker(&m_appendersLock);
-
- if (!m_appenders.isEmpty())
- {
- foreach (AbstractAppender* appender, m_appenders)
- appender->write(timeStamp, logLevel, file, line, function, message);
- }
- else
- {
- // Fallback
- QString result = QString(QLatin1String("[%1] <%2> %3")).arg(Logger::levelToString(logLevel), -7)
- .arg(function).arg(message);
-
- std::cerr << qPrintable(result) << std::endl;
- }
-
- if (logLevel == Logger::Fatal)
- abort();
- }
-
-
- void write(Logger::LogLevel logLevel, const char* file, int line, const char* function, const QString& message)
- {
- write(QDateTime::currentDateTime(), logLevel, file, line, function, message);
- }
-
-
- void write(Logger::LogLevel logLevel, const char* file, int line, const char* function, const char* message)
- {
- write(logLevel, file, line, function, QString(message));
- }
-
-
- QDebug write(Logger::LogLevel logLevel, const char* file, int line, const char* function)
- {
- LogDevice* d = logDevice();
- d->lock(logLevel, file, line, function);
- return QDebug(d);
- }
-
-
- void writeAssert(const char* file, int line, const char* function, const char* condition)
- {
- write(Logger::Fatal, file, line, function, QString("ASSERT: \"%1\"").arg(condition));
- }
-
- private:
- QList<AbstractAppender*> m_appenders;
- QReadWriteLock m_appendersLock;
-
- LogDevice* m_logDevice;
- QReadWriteLock m_logDeviceLock;
-};
-
-// Static fields initialization
-LoggerPrivate* LoggerPrivate::m_self = 0;
-QReadWriteLock LoggerPrivate::m_selfLock;
-
-
-static void cleanupLoggerPrivate()
-{
- QWriteLocker locker(&LoggerPrivate::m_selfLock);
-
- delete LoggerPrivate::m_self;
- LoggerPrivate::m_self = 0;
-}
-
-
-#if QT_VERSION >= 0x050000
-static void qtLoggerMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
-{
- Logger::LogLevel level;
- switch (type)
- {
- case QtDebugMsg:
- level = Logger::Debug;
- break;
- case QtWarningMsg:
- level = Logger::Warning;
- break;
- case QtCriticalMsg:
- level = Logger::Error;
- break;
- case QtFatalMsg:
- level = Logger::Fatal;
- break;
- }
-
- Logger::write(level, context.file, context.line, context.function, msg);
-}
-
-#else
-
-static void qtLoggerMessageHandler(QtMsgType type, const char* msg)
-{
- switch (type)
- {
- case QtDebugMsg:
- LOG_DEBUG(msg);
- break;
- case QtWarningMsg:
- LOG_WARNING(msg);
- break;
- case QtCriticalMsg:
- LOG_ERROR(msg);
- break;
- case QtFatalMsg:
- LOG_FATAL(msg);
- break;
- }
-}
-#endif
-
-
-QString Logger::levelToString(Logger::LogLevel logLevel)
-{
- switch (logLevel)
- {
- case Trace:
- return QLatin1String("Trace");
- case Debug:
- return QLatin1String("Debug");
- case Info:
- return QLatin1String("Info");
- case Warning:
- return QLatin1String("Warning");
- case Error:
- return QLatin1String("Error");
- case Fatal:
- return QLatin1String("Fatal");
- }
-
- return QString();
-}
-
-
-Logger::LogLevel Logger::levelFromString(const QString& s)
-{
- QString str = s.trimmed().toLower();
-
- LogLevel result = Debug;
-
- if (str == QLatin1String("trace"))
- result = Trace;
- else if (str == QLatin1String("debug"))
- result = Debug;
- else if (str == QLatin1String("info"))
- result = Info;
- else if (str == QLatin1String("warning"))
- result = Warning;
- else if (str == QLatin1String("error"))
- result = Error;
- else if (str == QLatin1String("fatal"))
- result = Fatal;
-
- return result;
-}
-
-
-void Logger::registerAppender(AbstractAppender* appender)
-{
- LoggerPrivate::instance()->registerAppender(appender);
-}
-
-
-void Logger::write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function,
- const QString& message)
-{
- LoggerPrivate::instance()->write(timeStamp, logLevel, file, line, function, message);
-}
-
-
-void Logger::write(LogLevel logLevel, const char* file, int line, const char* function, const QString& message)
-{
- LoggerPrivate::instance()->write(logLevel, file, line, function, message);
-}
-
-
-void Logger::write(LogLevel logLevel, const char* file, int line, const char* function, const char* message, ...)
-{
- va_list va;
- va_start(va, message);
- LoggerPrivate::instance()->write(logLevel, file, line, function, QString().vsprintf(message,va));
- va_end(va);
-}
-
-QDebug Logger::write(LogLevel logLevel, const char* file, int line, const char* function)
-{
- return LoggerPrivate::instance()->write(logLevel, file, line, function);
-}
-
-
-void Logger::writeAssert(const char* file, int line, const char* function, const char* condition)
-{
- LoggerPrivate::instance()->writeAssert(file, line, function, condition);
-}
diff --git a/rbutil/rbutilqt/logger/Logger.h b/rbutil/rbutilqt/logger/Logger.h
deleted file mode 100644
index d056dfc25d..0000000000
--- a/rbutil/rbutilqt/logger/Logger.h
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- Copyright (c) 2010 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.
-*/
-#ifndef LOGGER_H
-#define LOGGER_H
-/**
- * \file Logger.h
- * \brief A file containing the description of Logger class and and additional useful macros for logging
- */
-
-// Qt
-#include <QString>
-#include <QDebug>
-class QDateTime;
-
-// Local
-#include "CuteLogger_global.h"
-class AbstractAppender;
-
-
-//! 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.
- *
- * It is checked to work with GCC 4.4 or later.
- *
- * \sa Logger::LogLevel
- * \sa Logger::write()
- */
-#define LOG_TRACE(...) Logger::write(Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO, ##__VA_ARGS__)
-
-//! Writes the debug log record
-/**
- * This macro records the info log record using the Logger::write() function. It works identically to the LOG_TRACE()
- * macro.
- *
- * \sa LOG_TRACE()
- * \sa Logger::LogLevel
- * \sa Logger::write()
- */
-#define LOG_DEBUG(...) Logger::write(Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO, ##__VA_ARGS__)
-
-//! Write the info log record
-/**
- * This macro records the info log record using the Logger::write() function. It works identically to the LOG_TRACE()
- * macro.
- *
- * \sa LOG_TRACE()
- * \sa Logger::LogLevel
- * \sa Logger::write()
- */
-#define LOG_INFO(...) Logger::write(Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO, ##__VA_ARGS__)
-
-//! Write the warning log record
-/**
- * This macro records the warning log record using the Logger::write() function. It works identically to the LOG_TRACE()
- * macro.
- *
- * \sa LOG_TRACE()
- * \sa Logger::LogLevel
- * \sa Logger::write()
- */
-#define LOG_WARNING(...) Logger::write(Logger::Warning, __FILE__, __LINE__, Q_FUNC_INFO, ##__VA_ARGS__)
-
-//! Write the error log record
-/**
- * This macro records the error log record using the Logger::write() function. It works identically to the LOG_TRACE()
- * macro.
- *
- * \sa LOG_TRACE()
- * \sa Logger::LogLevel
- * \sa Logger::write()
- */
-#define LOG_ERROR(...) Logger::write(Logger::Error, __FILE__, __LINE__, Q_FUNC_INFO, ##__VA_ARGS__)
-
-//! Write the fatal log record
-/**
- * This macro records the fatal log record using the Logger::write() function. It works identically 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()
- */
-#define LOG_FATAL(...) Logger::write(Logger::Fatal, __FILE__, __LINE__, Q_FUNC_INFO, ##__VA_ARGS__)
-
-//! 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()
- */
-#define LOG_ASSERT(cond) ((!(cond)) ? Logger::writeAssert(__FILE__, __LINE__, Q_FUNC_INFO, #cond) : qt_noop())
-
-
-/**
- * \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 <QCoreApplication>
- *
- * #include <Logger.h>
- * #include <ConsoleAppender.h>
- *
- * int main(int argc, char* argv[])
- * {
- * QCoreApplication app(argc, argv);
- * ...
- * ConsoleAppender* consoleAppender = new ConsoleAppender();
- * consoleAppender->setFormat("[%-7l] <%C> %m\n");
- * Logger::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 similiar calls with
- * similiar Logger macros (e.g. LOG_DEBUG)
- *
- * \note Logger uses a singleton class which must live through all the application life cycle and cleans it on the
- * 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 AbstractAppender
- * \sa LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_FATAL
- * \sa LOG_ASSERT
- */
-
-//! Very simple but rather powerful component which may be used for logging your application activities.
-class CUTELOGGERSHARED_EXPORT Logger
-{
- public:
- //! Describes the possible severity levels of the log records
- enum LogLevel
- {
- Trace, //!< Trace level. Can be used for mostly unneeded records used for internal code tracing.
- Debug, //!< Debug level. Useful for non-necessary records used for the debugging of the software.
- Info, //!< Info level. Can be used for informational records, which may be interesting for not only developers.
- Warning, //!< Warning. May be used to log some non-fatal warnings detected by your application.
- Error, //!< Error. May be used for a big problems making your application work wrong but not crashing.
- Fatal //!< Fatal. Used for unrecoverable errors, crashes the application right after the log record is written.
- };
-
- //! Converts the LogLevel enum value to its string representation
- /**
- * \param logLevel Log level to convert
- *
- * \sa LogLevel
- * \sa levelFromString()
- */
- static QString levelToString(LogLevel logLevel);
-
- //! Converts the LogLevel string representation to enum value
- /**
- * Comparation of the strings is case independent. If the log level string provided cannot be understood
- * Logger::Debug is returned.
- *
- * \param s String to be decoded
- *
- * \sa LogLevel
- * \sa levelToString()
- */
- static LogLevel levelFromString(const QString& s);
-
- //! Registers the appender to write the log records to
- /**
- * On the log writing call (using one of the macros or the write() function) Logger traverses through the list of
- * the appenders and writes a log records to the each of them. Please, look through the AbstractAppender
- * documentation to understand the concept of appenders.
- *
- * If no appenders was added to Logger, it falls back to logging into the \c std::cerr STL stream.
- *
- * \param appender Appender to register in the Logger
- *
- * \note Logger takes ownership on the appender and it will delete it on the application exit. According to this,
- * appenders must be created on heap to prevent double destruction of the appender.
- *
- * \sa AbstractAppender
- */
- static void registerAppender(AbstractAppender* appender);
-
- //! Writes the log record
- /**
- * Writes the log records with the supplied arguments to all the registered appenders.
- *
- * \note It is not recommended to call this function directly. Instead of this you can just call one of the macros
- * (LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_FATAL) that will supply all the needed
- * information to this function.
- *
- * \param timeStamp - the time stamp of the record
- * \param logLevel - the log level of the record
- * \param file - the name of the source file that requested the log record
- * \param line - the line of the code of source file that requested the log record
- * \param function - name of the function that requested the log record
- * \param message - log message
- *
- * \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 LogLevel
- * \sa LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_FATAL
- * \sa AbstractAppender
- */
- static void write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function,
- const QString& message);
-
- /**
- * This is the overloaded function provided for the convinience. It behaves identically to the above function.
- *
- * This function uses the current timestamp obtained with \c QDateTime::currentDateTime().
- *
- * \sa write()
- */
- static void write(LogLevel logLevel, const char* file, int line, const char* function, const QString& message);
-
- /**
- * This is the overloaded function provided for the convinience. It behaves identically to the above function.
- *
- * This function uses the current timestamp obtained with \c QDateTime::currentDateTime(). Also it supports writing
- * <tt>const char*</tt> instead of \c QString and converts it internally using the \c QString::fromAscii(). If you
- * want this function to support the non-ascii strings, you will need to setup the codec using the
- * \c QTextCodec::setCodecForCStrings()
- *
- * \sa write()
- */
- static void write(LogLevel logLevel, const char* file, int line, const char* function, const char* message, ...);
-
- /**
- * This is the overloaded function provided for the convinience. It behaves identically to the above function.
- *
- * This function doesn't accept any log message as argument. It returns the \c QDebug object that can be written
- * using the stream functions. For example, you may like to write:
- * \code
- * LOG_DEBUG() << "This is the size" << size << "of the element" << elementName;
- * \endcode
- * instead of writing
- * \code
- * LOG_DEBUG(QString(QLatin1String("This is the size %1x%2 of the element %3"))
- * .arg(size.x()).arg(size.y()).arg(elementName));
- * \endcode
- *
- * Please consider reading the Qt Reference Documentation for the description of the QDebug class usage syntax.
- *
- * \note This overload is definitely more pleasant to use than the first write() overload, but it behaves definitely
- * slower than all the above overloads.
- *
- * \sa write()
- */
- static QDebug write(LogLevel logLevel, const char* file, int line, const char* function);
-
- //! Writes the assertion
- /**
- * This function writes the assertion record using the write() function.
- *
- * The assertion record is always written using the Logger::Fatal log level which leads to the abortation of the
- * program and generation of the core dump (if supported).
- *
- * The message written to the appenders will be identical to the \c condition argument prefixed with the
- * <tt>ASSERT:</tt> notification.
- *
- * \note It is not recommended to call this function directly. Instead of this you can just call the LOG_ASSERT
- * macro that will supply all the needed information to this function.
- *
- * \sa LOG_ASSERT
- * \sa write()
- */
- static void writeAssert(const char* file, int line, const char* function, const char* condition);
-};
-
-#endif // LOGGER_H
diff --git a/rbutil/rbutilqt/logger/README.ROCKBOX b/rbutil/rbutilqt/logger/README.ROCKBOX
index 08f537fb3f..f501a410dd 100644
--- a/rbutil/rbutilqt/logger/README.ROCKBOX
+++ b/rbutil/rbutilqt/logger/README.ROCKBOX
@@ -1,7 +1,7 @@
This folder contains the cutelogger project for logging functionality.
These files are distributed under the LGPL v2 or later.
The source files have been last synced with the projects at
-https://gitorious.org/cutelogger to commit
-e3c2745c6c5f38896f87472e01ea2caf2d9e211b.
-
+https://github.com/dept2/CuteLogger/ to commit
+5ae6b9ac13e0cc2821d236e3542a83990b63c95c
+on Aug 7, 2020.
diff --git a/rbutil/rbutilqt/logger/include/AbstractAppender.h b/rbutil/rbutilqt/logger/include/AbstractAppender.h
new file mode 100644
index 0000000000..e029b045aa
--- /dev/null
+++ b/rbutil/rbutilqt/logger/include/AbstractAppender.h
@@ -0,0 +1,49 @@
+/*
+ Copyright (c) 2010 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.
+*/
+#ifndef ABSTRACTAPPENDER_H
+#define ABSTRACTAPPENDER_H
+
+// Local
+#include "CuteLogger_global.h"
+#include <Logger.h>
+
+// Qt
+#include <QMutex>
+
+
+class CUTELOGGERSHARED_EXPORT AbstractAppender
+{
+ public:
+ AbstractAppender();
+ virtual ~AbstractAppender();
+
+ Logger::LogLevel detailsLevel() const;
+ void setDetailsLevel(Logger::LogLevel level);
+ void setDetailsLevel(const QString& level);
+
+ void write(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line, const char* function,
+ const QString& category, const QString& message);
+
+ protected:
+ virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
+ const char* function, const QString& category, const QString& message) = 0;
+
+ private:
+ QMutex m_writeMutex;
+
+ Logger::LogLevel m_detailsLevel;
+ mutable QMutex m_detailsLevelMutex;
+};
+
+#endif // ABSTRACTAPPENDER_H
diff --git a/rbutil/rbutilqt/logger/include/AbstractStringAppender.h b/rbutil/rbutilqt/logger/include/AbstractStringAppender.h
new file mode 100644
index 0000000000..78df9e6176
--- /dev/null
+++ b/rbutil/rbutilqt/logger/include/AbstractStringAppender.h
@@ -0,0 +1,46 @@
+/*
+ Copyright (c) 2010 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.
+*/
+#ifndef ABSTRACTSTRINGAPPENDER_H
+#define ABSTRACTSTRINGAPPENDER_H
+
+// Local
+#include "CuteLogger_global.h"
+#include <AbstractAppender.h>
+
+// Qt
+#include <QReadWriteLock>
+
+
+class CUTELOGGERSHARED_EXPORT AbstractStringAppender : public AbstractAppender
+{
+ public:
+ AbstractStringAppender();
+
+ virtual QString format() const;
+ void setFormat(const QString&);
+
+ static QString stripFunctionName(const char*);
+
+ protected:
+ QString formattedString(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
+ const char* function, const QString& category, const QString& message) const;
+
+ private:
+ static QByteArray qCleanupFuncinfo(const char*);
+
+ QString m_format;
+ mutable QReadWriteLock m_formatLock;
+};
+
+#endif // ABSTRACTSTRINGAPPENDER_H
diff --git a/rbutil/rbutilqt/logger/ConsoleAppender.h b/rbutil/rbutilqt/logger/include/ConsoleAppender.h
index fa685b5e82..64ef2e7a19 100644
--- a/rbutil/rbutilqt/logger/ConsoleAppender.h
+++ b/rbutil/rbutilqt/logger/include/ConsoleAppender.h
@@ -16,17 +16,21 @@
#include "CuteLogger_global.h"
#include <AbstractStringAppender.h>
-
-//! ConsoleAppender is the simple appender that writes the log records to the std::cerr output stream.
+
+
class CUTELOGGERSHARED_EXPORT ConsoleAppender : public AbstractStringAppender
{
+ public:
+ ConsoleAppender();
+ virtual QString format() const;
+ void ignoreEnvironmentPattern(bool ignore);
+
protected:
- //! Writes the log record to the std::cerr stream.
- /**
- * \sa AbstractStringAppender::format()
- */
virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
- const char* function, const QString& message);
+ const char* function, const QString& category, const QString& message);
+
+ private:
+ bool m_ignoreEnvPattern;
};
#endif // CONSOLEAPPENDER_H
diff --git a/rbutil/rbutilqt/logger/CuteLogger_global.h b/rbutil/rbutilqt/logger/include/CuteLogger_global.h
index c5e7680845..c5e7680845 100644
--- a/rbutil/rbutilqt/logger/CuteLogger_global.h
+++ b/rbutil/rbutilqt/logger/include/CuteLogger_global.h
diff --git a/rbutil/rbutilqt/logger/FileAppender.h b/rbutil/rbutilqt/logger/include/FileAppender.h
index 70a70c3e43..ab9e12a91d 100644
--- a/rbutil/rbutilqt/logger/FileAppender.h
+++ b/rbutil/rbutilqt/logger/include/FileAppender.h
@@ -23,34 +23,20 @@
#include <QTextStream>
-//! File is the simple appender that writes the log records to the plain text file.
class CUTELOGGERSHARED_EXPORT FileAppender : public AbstractStringAppender
{
public:
- //! Constructs the new file appender assigned to file with the given name.
FileAppender(const QString& fileName = QString());
~FileAppender();
- //! Returns the name set by setFileName() or to the FileAppender constructor.
- /**
- * \sa setFileName()
- */
QString fileName() const;
-
- //! Sets the name of the file. The name can have no path, a relative path, or an absolute path.
- /**
- * \sa fileName()
- */
void setFileName(const QString&);
+ bool reopenFile();
+
protected:
- //! Write the log record to the file.
- /**
- * \sa fileName()
- * \sa AbstractStringAppender::format()
- */
virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
- const char* function, const QString& message);
+ const char* function, const QString& category, const QString& message);
bool openFile();
void closeFile();
diff --git a/rbutil/rbutilqt/logger/include/Logger.h b/rbutil/rbutilqt/logger/include/Logger.h
new file mode 100644
index 0000000000..509bc5f435
--- /dev/null
+++ b/rbutil/rbutilqt/logger/include/Logger.h
@@ -0,0 +1,237 @@
+/*
+ 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.
+*/
+#ifndef LOGGER_H
+#define LOGGER_H
+
+// Qt
+#include <QString>
+#include <QDebug>
+#include <QDateTime>
+
+// Local
+#include "CuteLogger_global.h"
+class AbstractAppender;
+
+
+class Logger;
+CUTELOGGERSHARED_EXPORT Logger* cuteLoggerInstance();
+#define cuteLogger cuteLoggerInstance()
+
+
+#define LOG_TRACE CuteMessageLogger(cuteLoggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO).write
+#define LOG_DEBUG CuteMessageLogger(cuteLoggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO).write
+#define LOG_INFO CuteMessageLogger(cuteLoggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO).write
+#define LOG_WARNING CuteMessageLogger(cuteLoggerInstance(), Logger::Warning, __FILE__, __LINE__, Q_FUNC_INFO).write
+#define LOG_ERROR CuteMessageLogger(cuteLoggerInstance(), Logger::Error, __FILE__, __LINE__, Q_FUNC_INFO).write
+#define LOG_FATAL CuteMessageLogger(cuteLoggerInstance(), Logger::Fatal, __FILE__, __LINE__, Q_FUNC_INFO).write
+
+#define LOG_CTRACE(category) CuteMessageLogger(cuteLoggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO, category).write()
+#define LOG_CDEBUG(category) CuteMessageLogger(cuteLoggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO, category).write()
+#define LOG_CINFO(category) CuteMessageLogger(cuteLoggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO, category).write()
+#define LOG_CWARNING(category) CuteMessageLogger(cuteLoggerInstance(), Logger::Warning, __FILE__, __LINE__, Q_FUNC_INFO, category).write()
+#define LOG_CERROR(category) CuteMessageLogger(cuteLoggerInstance(), Logger::Error, __FILE__, __LINE__, Q_FUNC_INFO, category).write()
+#define LOG_CFATAL(category) CuteMessageLogger(cuteLoggerInstance(), Logger::Fatal, __FILE__, __LINE__, Q_FUNC_INFO, category).write()
+
+#define LOG_TRACE_TIME LoggerTimingHelper loggerTimingHelper(cuteLoggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start
+#define LOG_DEBUG_TIME LoggerTimingHelper loggerTimingHelper(cuteLoggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start
+#define LOG_INFO_TIME LoggerTimingHelper loggerTimingHelper(cuteLoggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start
+
+#define LOG_ASSERT(cond) ((!(cond)) ? cuteLoggerInstance()->writeAssert(__FILE__, __LINE__, Q_FUNC_INFO, #cond) : qt_noop())
+#define LOG_ASSERT_X(cond, msg) ((!(cond)) ? cuteLoggerInstance()->writeAssert(__FILE__, __LINE__, Q_FUNC_INFO, msg) : qt_noop())
+
+#if (__cplusplus >= 201103L)
+#include <functional>
+
+#define LOG_CATEGORY(category) \
+ Logger customCuteLoggerInstance{category};\
+ std::function<Logger*()> cuteLoggerInstance = [&customCuteLoggerInstance]() {\
+ return &customCuteLoggerInstance;\
+ };\
+
+#define LOG_GLOBAL_CATEGORY(category) \
+ Logger customCuteLoggerInstance{category, true};\
+ std::function<Logger*()> cuteLoggerInstance = [&customCuteLoggerInstance]() {\
+ return &customCuteLoggerInstance;\
+ };\
+
+#else
+
+#define LOG_CATEGORY(category) \
+ Logger* cuteLoggerInstance()\
+ {\
+ static Logger customCuteLoggerInstance(category);\
+ return &customCuteLoggerInstance;\
+ }\
+
+#define LOG_GLOBAL_CATEGORY(category) \
+ Logger* cuteLoggerInstance()\
+ {\
+ static Logger customCuteLoggerInstance(category);\
+ customCuteLoggerInstance.logToGlobalInstance(category, true);\
+ return &customCuteLoggerInstance;\
+ }\
+
+#endif
+
+
+class LoggerPrivate;
+class CUTELOGGERSHARED_EXPORT Logger
+{
+ Q_DISABLE_COPY(Logger)
+
+ public:
+ Logger();
+ Logger(const QString& defaultCategory, bool writeToGlobalInstance = false);
+ ~Logger();
+
+ //! Describes the possible severity levels of the log records
+ enum LogLevel
+ {
+ Trace, //!< Trace level. Can be used for mostly unneeded records used for internal code tracing.
+ Debug, //!< Debug level. Useful for non-necessary records used for the debugging of the software.
+ Info, //!< Info level. Can be used for informational records, which may be interesting for not only developers.
+ Warning, //!< Warning. May be used to log some non-fatal warnings detected by your application.
+ Error, //!< Error. May be used for a big problems making your application work wrong but not crashing.
+ Fatal //!< Fatal. Used for unrecoverable errors, crashes the application right after the log record is written.
+ };
+
+ //! Sets the timing display mode for the LOG_TRACE_TIME, LOG_DEBUG_TIME and LOG_INFO_TIME macros
+ enum TimingMode
+ {
+ TimingAuto, //!< Show time in seconds, if it exceeds 10s (default)
+ TimingMs //!< Always use milliseconds to display
+ };
+
+ static QString levelToString(LogLevel logLevel);
+ static LogLevel levelFromString(const QString& s);
+
+ static Logger* globalInstance();
+
+ void registerAppender(AbstractAppender* appender);
+ void registerCategoryAppender(const QString& category, AbstractAppender* appender);
+
+ void removeAppender(AbstractAppender* appender);
+
+ void logToGlobalInstance(const QString& category, bool logToGlobal = false);
+
+ void setDefaultCategory(const QString& category);
+ QString defaultCategory() const;
+
+ void write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, const char* category,
+ const QString& message);
+ void write(LogLevel logLevel, const char* file, int line, const char* function, const char* category, const QString& message);
+
+ void writeAssert(const char* file, int line, const char* function, const char* condition);
+
+ private:
+ void write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, const char* category,
+ const QString& message, bool fromLocalInstance);
+ Q_DECLARE_PRIVATE(Logger)
+ LoggerPrivate* d_ptr;
+};
+
+
+class CUTELOGGERSHARED_EXPORT CuteMessageLogger
+{
+ Q_DISABLE_COPY(CuteMessageLogger)
+
+ public:
+ CuteMessageLogger(Logger* l, Logger::LogLevel level, const char* file, int line, const char* function)
+ : m_l(l),
+ m_level(level),
+ m_file(file),
+ m_line(line),
+ m_function(function),
+ m_category(nullptr)
+ {}
+
+ CuteMessageLogger(Logger* l, Logger::LogLevel level, const char* file, int line, const char* function, const char* category)
+ : m_l(l),
+ m_level(level),
+ m_file(file),
+ m_line(line),
+ m_function(function),
+ m_category(category)
+ {}
+
+ ~CuteMessageLogger();
+
+ void write(const char* msg, ...)
+#if defined(Q_CC_GNU) && !defined(__INSURE__)
+# if defined(Q_CC_MINGW) && !defined(Q_CC_CLANG)
+ __attribute__ ((format (gnu_printf, 2, 3)))
+# else
+ __attribute__ ((format (printf, 2, 3)))
+# endif
+#endif
+ ;
+
+ void write(const QString& msg);
+
+ QDebug write();
+
+ private:
+ Logger* m_l;
+ Logger::LogLevel m_level;
+ const char* m_file;
+ int m_line;
+ const char* m_function;
+ const char* m_category;
+ QString m_message;
+};
+
+
+class CUTELOGGERSHARED_EXPORT LoggerTimingHelper
+{
+ Q_DISABLE_COPY(LoggerTimingHelper)
+
+ public:
+ inline explicit LoggerTimingHelper(Logger* l, Logger::LogLevel logLevel, const char* file, int line,
+ const char* function)
+ : m_logger(l),
+ m_logLevel(logLevel),
+ m_timingMode(Logger::TimingAuto),
+ m_file(file),
+ m_line(line),
+ m_function(function)
+ {}
+
+ void start(const char* msg, ...)
+#if defined(Q_CC_GNU) && !defined(__INSURE__)
+ # if defined(Q_CC_MINGW) && !defined(Q_CC_CLANG)
+ __attribute__ ((format (gnu_printf, 2, 3)))
+ # else
+ __attribute__ ((format (printf, 2, 3)))
+ # endif
+#endif
+ ;
+
+ void start(const QString& msg = QString());
+ void start(Logger::TimingMode mode, const QString& msg);
+
+ ~LoggerTimingHelper();
+
+ private:
+ Logger* m_logger;
+ QTime m_time;
+ Logger::LogLevel m_logLevel;
+ Logger::TimingMode m_timingMode;
+ const char* m_file;
+ int m_line;
+ const char* m_function;
+ QString m_block;
+};
+
+
+#endif // LOGGER_H
diff --git a/rbutil/rbutilqt/logger/OutputDebugAppender.h b/rbutil/rbutilqt/logger/include/OutputDebugAppender.h
index f5a5b8c588..dd7ad4deb7 100644
--- a/rbutil/rbutilqt/logger/OutputDebugAppender.h
+++ b/rbutil/rbutilqt/logger/include/OutputDebugAppender.h
@@ -18,16 +18,12 @@
#include "CuteLogger_global.h"
#include <AbstractStringAppender.h>
-//! OutputDebugAppender is the appender that writes the log records to the Microsoft Debug Log
+
class CUTELOGGERSHARED_EXPORT OutputDebugAppender : public AbstractStringAppender
{
protected:
- //! Writes the log record to the windows debug log.
- /**
- * \sa AbstractStringAppender::format()
- */
virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
- const char* function, const QString& message);
+ const char* function, const QString& category, const QString& message);
};
#endif // OUTPUTDEBUGAPPENDER_H
diff --git a/rbutil/rbutilqt/logger/logger.pri b/rbutil/rbutilqt/logger/logger.pri
index ec8d68b399..e34bccb3cf 100644
--- a/rbutil/rbutilqt/logger/logger.pri
+++ b/rbutil/rbutilqt/logger/logger.pri
@@ -1,19 +1,22 @@
SOURCES += \
- $$PWD/AbstractAppender.cpp \
- $$PWD/AbstractStringAppender.cpp \
- $$PWD/ConsoleAppender.cpp \
- $$PWD/FileAppender.cpp \
- $$PWD/Logger.cpp \
+ $$PWD/src/AbstractAppender.cpp \
+ $$PWD/src/AbstractStringAppender.cpp \
+ $$PWD/src/ConsoleAppender.cpp \
+ $$PWD/src/FileAppender.cpp \
+ $$PWD/src/Logger.cpp \
-INCLUDES += \
- $$PWD/AbstractAppender.h \
- $$PWD/ConsoleAppender.h \
- $$PWD/FileAppender.h \
- $$PWD/OutputDebugAppender.h \
- $$PWD/AbstractStringAppender.h \
- $$PWD/CuteLogger_global.h \
- $$PWD/Logger.h \
+HEADERS += \
+ $$PWD/include/AbstractAppender.h \
+ $$PWD/include/ConsoleAppender.h \
+ $$PWD/include/FileAppender.h \
+ $$PWD/include/OutputDebugAppender.h \
+ $$PWD/include/AbstractStringAppender.h \
+ $$PWD/include/CuteLogger_global.h \
+ $$PWD/include/Logger.h \
+
+INCLUDEPATH += $$PWD/include
DEFINES += \
CUTELOGGER_STATIC
+
diff --git a/rbutil/rbutilqt/logger/src/AbstractAppender.cpp b/rbutil/rbutilqt/logger/src/AbstractAppender.cpp
new file mode 100644
index 0000000000..778bbddd11
--- /dev/null
+++ b/rbutil/rbutilqt/logger/src/AbstractAppender.cpp
@@ -0,0 +1,147 @@
+/*
+ Copyright (c) 2010 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 "AbstractAppender.h"
+
+// Qt
+#include <QMutexLocker>
+
+
+/**
+ * \class AbstractAppender
+ *
+ * \brief The AbstractAppender class provides an abstract base class for writing a log entries.
+ *
+ * The AbstractAppender class is the base interface class for all log appenders that could be used with Logger.
+ *
+ * AbstractAppender provides a common implementation for the thread safe, mutex-protected logging of application
+ * messages, such as ConsoleAppender, FileAppender or something else. AbstractAppender is abstract and can not be
+ * instantiated, but you can use any of its subclasses or create a custom log appender at your choice.
+ *
+ * Appenders are the logical devices that is aimed to be attached to Logger object by calling
+ * Logger::registerAppender(). On each log record call from the application Logger object sequentially calls write()
+ * function on all the appenders registered in it.
+ *
+ * You can subclass AbstractAppender to implement a logging target of any kind you like. It may be the external logging
+ * subsystem (for example, syslog in *nix), XML file, SQL database entries, D-Bus messages or anything else you can
+ * imagine.
+ *
+ * For the simple non-structured plain text logging (for example, to a plain text file or to the console output) you may
+ * like to subclass the AbstractStringAppender instead of AbstractAppender, which will give you a more convinient way to
+ * control the format of the log output.
+ *
+ * \sa AbstractStringAppender
+ * \sa Logger::registerAppender()
+ */
+
+
+//! Constructs a AbstractAppender object.
+AbstractAppender::AbstractAppender()
+ : m_detailsLevel(Logger::Debug)
+{}
+
+
+//! Destructs the AbstractAppender object.
+AbstractAppender::~AbstractAppender()
+{}
+
+
+//! Returns the current details level of appender.
+/**
+ * Log records with a log level lower than a current detailsLevel() will be silently ignored by appender and would not
+ * be sent to its append() function.
+ *
+ * It provides additional logging flexibility, allowing you to set the different severity levels for different types
+ * of logs.
+ *
+ * \note This function is thread safe.
+ *
+ * \sa setDetailsLevel()
+ * \sa Logger::LogLevel
+ */
+Logger::LogLevel AbstractAppender::detailsLevel() const
+{
+ QMutexLocker locker(&m_detailsLevelMutex);
+ return m_detailsLevel;
+}
+
+
+//! Sets the current details level of appender.
+/**
+ * Default details level is Logger::Debug
+ *
+ * \note This function is thread safe.
+ *
+ * \sa detailsLevel()
+ * \sa Logger::LogLevel
+ */
+void AbstractAppender::setDetailsLevel(Logger::LogLevel level)
+{
+ QMutexLocker locker(&m_detailsLevelMutex);
+ m_detailsLevel = level;
+}
+
+
+
+//! Sets the current details level of appender
+/**
+ * This function is provided for convenience, it behaves like an above function.
+ *
+ * \sa detailsLevel()
+ * \sa Logger::LogLevel
+ */
+void AbstractAppender::setDetailsLevel(const QString& level)
+{
+ setDetailsLevel(Logger::levelFromString(level));
+}
+
+
+//! Tries to write the log record to this logger
+/**
+ * This is the function called by Logger object to write a log message to the appender.
+ *
+ * \note This function is thread safe.
+ *
+ * \sa Logger::write()
+ * \sa detailsLevel()
+ */
+void AbstractAppender::write(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
+ const char* function, const QString& category, const QString& message)
+{
+ if (logLevel >= detailsLevel())
+ {
+ QMutexLocker locker(&m_writeMutex);
+ append(timeStamp, logLevel, file, line, function, category, message);
+ }
+}
+
+
+/**
+ * \fn virtual void AbstractAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file,
+ * int line, const char* function, const QString& message)
+ *
+ * \brief Writes the log record to the logger instance
+ *
+ * This function is called every time when user tries to write a message to this AbstractAppender instance using
+ * the write() function. Write function works as proxy and transfers only the messages with log level more or equal
+ * to the current logLevel().
+ *
+ * Overload this function when you are implementing a custom appender.
+ *
+ * \note This function is not needed to be thread safe because it is never called directly by Logger object. The
+ * write() function works as a proxy and protects this function from concurrent access.
+ *
+ * \sa Logger::write()
+ */
+
diff --git a/rbutil/rbutilqt/logger/src/AbstractStringAppender.cpp b/rbutil/rbutilqt/logger/src/AbstractStringAppender.cpp
new file mode 100644
index 0000000000..ce64aaeb43
--- /dev/null
+++ b/rbutil/rbutilqt/logger/src/AbstractStringAppender.cpp
@@ -0,0 +1,459 @@
+/*
+ Copyright (c) 2010 Boris Moiseev (cyberbobs at gmail dot com) Nikolay Matyunin (matyunin.n at gmail dot com)
+
+ Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+
+ 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 "AbstractStringAppender.h"
+
+// Qt
+#include <QReadLocker>
+#include <QWriteLocker>
+#include <QDateTime>
+#include <QRegExp>
+#include <QCoreApplication>
+#include <QThread>
+
+
+/**
+ * \class AbstractStringAppender
+ *
+ * \brief The AbstractStringAppender class provides a convinient base for appenders working with plain text formatted
+ * logs.
+ *
+ * AbstractSringAppender is the simple extension of the AbstractAppender class providing the convinient way to create
+ * custom log appenders working with a plain text formatted log targets.
+ *
+ * It have the formattedString() protected function that formats the logging arguments according to a format set with
+ * setFormat().
+ *
+ * This class can not be directly instantiated because it contains pure virtual function inherited from AbstractAppender
+ * class.
+ *
+ * For more detailed description of customizing the log output format see the documentation on the setFormat() function.
+ */
+
+
+const char formattingMarker = '%';
+
+
+//! Constructs a new string appender object
+AbstractStringAppender::AbstractStringAppender()
+ : m_format(QLatin1String("%{time}{yyyy-MM-ddTHH:mm:ss.zzz} [%{type:-7}] <%{function}> %{message}\n"))
+{}
+
+
+//! Returns the current log format string.
+/**
+ * The default format is set to "%{time}{yyyy-MM-ddTHH:mm:ss.zzz} [%{type:-7}] <%{function}> %{message}\n". You can set a different log record
+ * format using the setFormat() function.
+ *
+ * \sa setFormat(const QString&)
+ */
+QString AbstractStringAppender::format() const
+{
+ QReadLocker locker(&m_formatLock);
+ return m_format;
+}
+
+
+//! Sets the logging format for writing strings to the log target with this appender.
+/**
+ * The string format seems to be very common to those developers who have used a standart sprintf function.
+ *
+ * Log output format is a simple QString with the special markers (starting with % sign) which will be replaced with
+ * it's internal meaning when writing a log record.
+ *
+ * Controlling marker begins with the percent sign (%) which is followed by the command inside {} brackets
+ * (the command describes, what will be put to log record instead of marker).
+ * Optional field width argument may be specified right after the command (through the colon symbol before the closing bracket)
+ * Some commands requires an additional formatting argument (in the second {} brackets).
+ *
+ * Field width argument works almost identically to the \c QString::arg() \c fieldWidth argument (and uses it
+ * internally). For example, \c "%{type:-7}" will be replaced with the left padded debug level of the message
+ * (\c "Debug ") or something. For the more detailed description of it you may consider to look to the Qt
+ * Reference Documentation.
+ *
+ * Supported marker commands are:
+ * \arg \c %{time} - timestamp. You may specify your custom timestamp format using the second {} brackets after the marker,
+ * timestamp format here will be similiar to those used in QDateTime::toString() function. For example,
+ * "%{time}{dd-MM-yyyy, HH:mm}" may be replaced with "17-12-2010, 20:17" depending on current date and time.
+ * The default format used here is "HH:mm:ss.zzz".
+ * \arg \c %{type} - Log level. Possible log levels are shown in the Logger::LogLevel enumerator.
+ * \arg \c %{Type} - Uppercased log level.
+ * \arg \c %{typeOne} - One letter log level.
+ * \arg \c %{TypeOne} - One uppercase letter log level.
+ * \arg \c %{File} - Full source file name (with path) of the file that requested log recording. Uses the \c __FILE__
+ * preprocessor macro.
+ * \arg \c %{file} - Short file name (with stripped path).
+ * \arg \c %{line} - Line number in the source file. Uses the \c __LINE__ preprocessor macro.
+ * \arg \c %{Function} - Name of function that called on of the LOG_* macros. Uses the \c Q_FUNC_INFO macro provided with
+ * Qt.
+ * \arg \c %{function} - Similiar to the %{Function}, but the function name is stripped using stripFunctionName
+ * \arg \c %{message} - The log message sent by the caller.
+ * \arg \c %{category} - The log category.
+ * \arg \c %{appname} - Application name (returned by QCoreApplication::applicationName() function).
+ * \arg \c %{pid} - Application pid (returned by QCoreApplication::applicationPid() function).
+ * \arg \c %{threadid} - ID of current thread.
+ * \arg \c %% - Convinient marker that is replaced with the single \c % mark.
+ *
+ * \note Format doesn't add \c '\\n' to the end of the format line. Please consider adding it manually.
+ *
+ * \sa format()
+ * \sa stripFunctionName()
+ * \sa Logger::LogLevel
+ */
+void AbstractStringAppender::setFormat(const QString& format)
+{
+ QWriteLocker locker(&m_formatLock);
+ m_format = format;
+}
+
+
+//! Strips the long function signature (as added by Q_FUNC_INFO macro)
+/**
+ * The string processing drops the returning type, arguments and template parameters of function. It is definitely
+ * useful for enchancing the log output readability.
+ * \return stripped function name
+ */
+QString AbstractStringAppender::stripFunctionName(const char* name)
+{
+ return QString::fromLatin1(qCleanupFuncinfo(name));
+}
+
+
+// The function was backported from Qt5 sources (qlogging.h)
+QByteArray AbstractStringAppender::qCleanupFuncinfo(const char* name)
+{
+ QByteArray info(name);
+
+ // Strip the function info down to the base function name
+ // note that this throws away the template definitions,
+ // the parameter types (overloads) and any const/volatile qualifiers.
+ if (info.isEmpty())
+ return info;
+
+ int pos;
+
+ // skip trailing [with XXX] for templates (gcc)
+ pos = info.size() - 1;
+ if (info.endsWith(']')) {
+ while (--pos) {
+ if (info.at(pos) == '[')
+ info.truncate(pos);
+ }
+ }
+
+ bool hasLambda = false;
+ QRegExp lambdaRegex("::<lambda\\(.*\\)>");
+ int lambdaIndex = lambdaRegex.indexIn(QString::fromLatin1(info));
+ if (lambdaIndex != -1)
+ {
+ hasLambda = true;
+ info.remove(lambdaIndex, lambdaRegex.matchedLength());
+ }
+
+ // operator names with '(', ')', '<', '>' in it
+ static const char operator_call[] = "operator()";
+ static const char operator_lessThan[] = "operator<";
+ static const char operator_greaterThan[] = "operator>";
+ static const char operator_lessThanEqual[] = "operator<=";
+ static const char operator_greaterThanEqual[] = "operator>=";
+
+ // canonize operator names
+ info.replace("operator ", "operator");
+
+ // remove argument list
+ forever {
+ int parencount = 0;
+ pos = info.lastIndexOf(')');
+ if (pos == -1) {
+ // Don't know how to parse this function name
+ return info;
+ }
+
+ // find the beginning of the argument list
+ --pos;
+ ++parencount;
+ while (pos && parencount) {
+ if (info.at(pos) == ')')
+ ++parencount;
+ else if (info.at(pos) == '(')
+ --parencount;
+ --pos;
+ }
+ if (parencount != 0)
+ return info;
+
+ info.truncate(++pos);
+
+ if (info.at(pos - 1) == ')') {
+ if (info.indexOf(operator_call) == pos - (int)strlen(operator_call))
+ break;
+
+ // this function returns a pointer to a function
+ // and we matched the arguments of the return type's parameter list
+ // try again
+ info.remove(0, info.indexOf('('));
+ info.chop(1);
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ if (hasLambda)
+ info.append("::lambda");
+
+ // find the beginning of the function name
+ int parencount = 0;
+ int templatecount = 0;
+ --pos;
+
+ // make sure special characters in operator names are kept
+ if (pos > -1) {
+ switch (info.at(pos)) {
+ case ')':
+ if (info.indexOf(operator_call) == pos - (int)strlen(operator_call) + 1)
+ pos -= 2;
+ break;
+ case '<':
+ if (info.indexOf(operator_lessThan) == pos - (int)strlen(operator_lessThan) + 1)
+ --pos;
+ break;
+ case '>':
+ if (info.indexOf(operator_greaterThan) == pos - (int)strlen(operator_greaterThan) + 1)
+ --pos;
+ break;
+ case '=': {
+ int operatorLength = (int)strlen(operator_lessThanEqual);
+ if (info.indexOf(operator_lessThanEqual) == pos - operatorLength + 1)
+ pos -= 2;
+ else if (info.indexOf(operator_greaterThanEqual) == pos - operatorLength + 1)
+ pos -= 2;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ while (pos > -1) {
+ if (parencount < 0 || templatecount < 0)
+ return info;
+
+ char c = info.at(pos);
+ if (c == ')')
+ ++parencount;
+ else if (c == '(')
+ --parencount;
+ else if (c == '>')
+ ++templatecount;
+ else if (c == '<')
+ --templatecount;
+ else if (c == ' ' && templatecount == 0 && parencount == 0)
+ break;
+
+ --pos;
+ }
+ info = info.mid(pos + 1);
+
+ // remove trailing '*', '&' that are part of the return argument
+ while ((info.at(0) == '*')
+ || (info.at(0) == '&'))
+ info = info.mid(1);
+
+ // we have the full function name now.
+ // clean up the templates
+ while ((pos = info.lastIndexOf('>')) != -1) {
+ if (!info.contains('<'))
+ break;
+
+ // find the matching close
+ int end = pos;
+ templatecount = 1;
+ --pos;
+ while (pos && templatecount) {
+ char c = info.at(pos);
+ if (c == '>')
+ ++templatecount;
+ else if (c == '<')
+ --templatecount;
+ --pos;
+ }
+ ++pos;
+ info.remove(pos, end - pos + 1);
+ }
+
+ return info;
+}
+
+
+//! Returns the string to record to the logging target, formatted according to the format().
+/**
+ * \sa format()
+ * \sa setFormat(const QString&)
+ */
+QString AbstractStringAppender::formattedString(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file,
+ int line, const char* function, const QString& category, const QString& message) const
+{
+ QString f = format();
+ const int size = f.size();
+
+ QString result;
+
+ int i = 0;
+ while (i < f.size())
+ {
+ QChar c = f.at(i);
+
+ // We will silently ignore the broken % marker at the end of string
+ if (c != QLatin1Char(formattingMarker) || (i + 2) >= size)
+ {
+ result.append(c);
+ }
+ else
+ {
+ i += 2;
+ QChar currentChar = f.at(i);
+ QString command;
+ int fieldWidth = 0;
+
+ if (currentChar.isLetter())
+ {
+ command.append(currentChar);
+ int j = 1;
+ while ((i + j) < size && f.at(i + j).isLetter())
+ {
+ command.append(f.at(i+j));
+ j++;
+ }
+
+ i+=j;
+ currentChar = f.at(i);
+
+ // Check for the padding instruction
+ if (currentChar == QLatin1Char(':'))
+ {
+ currentChar = f.at(++i);
+ if (currentChar.isDigit() || currentChar.category() == QChar::Punctuation_Dash)
+ {
+ int j = 1;
+ while ((i + j) < size && f.at(i + j).isDigit())
+ j++;
+ fieldWidth = f.mid(i, j).toInt();
+
+ i += j;
+ }
+ }
+ }
+
+ // Log record chunk to insert instead of formatting instruction
+ QString chunk;
+
+ // Time stamp
+ if (command == QLatin1String("time"))
+ {
+ if (f.at(i + 1) == QLatin1Char('{'))
+ {
+ int j = 1;
+ while ((i + 2 + j) < size && f.at(i + 2 + j) != QLatin1Char('}'))
+ j++;
+
+ if ((i + 2 + j) < size)
+ {
+ chunk = timeStamp.toString(f.mid(i + 2, j));
+
+ i += j;
+ i += 2;
+ }
+ }
+
+ if (chunk.isNull())
+ chunk = timeStamp.toString(QLatin1String("HH:mm:ss.zzz"));
+ }
+
+ // Log level
+ else if (command == QLatin1String("type"))
+ chunk = Logger::levelToString(logLevel);
+
+ // Uppercased log level
+ else if (command == QLatin1String("Type"))
+ chunk = Logger::levelToString(logLevel).toUpper();
+
+ // One letter log level
+ else if (command == QLatin1String("typeOne"))
+ chunk = Logger::levelToString(logLevel).left(1).toLower();
+
+ // One uppercase letter log level
+ else if (command == QLatin1String("TypeOne"))
+ chunk = Logger::levelToString(logLevel).left(1).toUpper();
+
+ // Filename
+ else if (command == QLatin1String("File"))
+ chunk = QLatin1String(file);
+
+ // Filename without a path
+ else if (command == QLatin1String("file"))
+ chunk = QString(QLatin1String(file)).section(QRegExp("[/\\\\]"), -1);
+
+ // Source line number
+ else if (command == QLatin1String("line"))
+ chunk = QString::number(line);
+
+ // Function name, as returned by Q_FUNC_INFO
+ else if (command == QLatin1String("Function"))
+ chunk = QString::fromLatin1(function);
+
+ // Stripped function name
+ else if (command == QLatin1String("function"))
+ chunk = stripFunctionName(function);
+
+ // Log message
+ else if (command == QLatin1String("message"))
+ chunk = message;
+
+ else if (command == QLatin1String("category"))
+ chunk = category;
+
+ // Application pid
+ else if (command == QLatin1String("pid"))
+ chunk = QString::number(QCoreApplication::applicationPid());
+
+ // Appplication name
+ else if (command == QLatin1String("appname"))
+ chunk = QCoreApplication::applicationName();
+
+ // Thread ID (duplicates Qt5 threadid debbuging way)
+ else if (command == QLatin1String("threadid"))
+ chunk = QLatin1String("0x") + QString::number(qlonglong(QThread::currentThread()->currentThread()), 16);
+
+ // We simply replace the double formatting marker (%) with one
+ else if (command == QString(formattingMarker))
+ chunk = QLatin1Char(formattingMarker);
+
+ // Do not process any unknown commands
+ else
+ {
+ chunk = QString(formattingMarker);
+ chunk.append(command);
+ }
+
+ result.append(QString(QLatin1String("%1")).arg(chunk, fieldWidth));
+ }
+
+ ++i;
+ }
+
+ return result;
+}
diff --git a/rbutil/rbutilqt/logger/src/ConsoleAppender.cpp b/rbutil/rbutilqt/logger/src/ConsoleAppender.cpp
new file mode 100644
index 0000000000..932ffab787
--- /dev/null
+++ b/rbutil/rbutilqt/logger/src/ConsoleAppender.cpp
@@ -0,0 +1,64 @@
+/*
+ Copyright (c) 2010 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 "ConsoleAppender.h"
+
+// STL
+#include <iostream>
+
+
+/**
+ * \class ConsoleAppender
+ *
+ * \brief ConsoleAppender is the simple appender that writes the log records to the std::cerr output stream.
+ *
+ * ConsoleAppender uses "[%{type:-7}] <%{function}> %{message}\n" as a default output format. It is similar to the
+ * AbstractStringAppender but doesn't show a timestamp.
+ *
+ * You can modify ConsoleAppender output format without modifying your code by using \c QT_MESSAGE_PATTERN environment
+ * variable. If you need your application to ignore this environment variable you can call
+ * ConsoleAppender::ignoreEnvironmentPattern(true)
+ */
+
+
+ConsoleAppender::ConsoleAppender()
+ : AbstractStringAppender()
+ , m_ignoreEnvPattern(false)
+{
+ setFormat("[%{type:-7}] <%{function}> %{message}\n");
+}
+
+
+QString ConsoleAppender::format() const
+{
+ const QString envPattern = QString::fromLocal8Bit(qgetenv("QT_MESSAGE_PATTERN"));
+ return (m_ignoreEnvPattern || envPattern.isEmpty()) ? AbstractStringAppender::format() : (envPattern + "\n");
+}
+
+
+void ConsoleAppender::ignoreEnvironmentPattern(bool ignore)
+{
+ m_ignoreEnvPattern = ignore;
+}
+
+
+//! Writes the log record to the std::cerr stream.
+/**
+ * \sa AbstractStringAppender::format()
+ */
+void ConsoleAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
+ const char* function, const QString& category, const QString& message)
+{
+ std::cerr << qPrintable(formattedString(timeStamp, logLevel, file, line, function, category, message));
+}
diff --git a/rbutil/rbutilqt/logger/FileAppender.cpp b/rbutil/rbutilqt/logger/src/FileAppender.cpp
index 3e4d0e22f9..b9018b0324 100644
--- a/rbutil/rbutilqt/logger/FileAppender.cpp
+++ b/rbutil/rbutilqt/logger/src/FileAppender.cpp
@@ -17,7 +17,14 @@
// STL
#include <iostream>
+/**
+ * \class FileAppender
+ *
+ * \brief Simple appender that writes the log records to the plain text file.
+ */
+
+//! Constructs the new file appender assigned to file with the given name.
FileAppender::FileAppender(const QString& fileName)
{
setFileName(fileName);
@@ -30,6 +37,10 @@ FileAppender::~FileAppender()
}
+//! Returns the name set by setFileName() or to the FileAppender constructor.
+/**
+ * \sa setFileName()
+ */
QString FileAppender::fileName() const
{
QMutexLocker locker(&m_logFileMutex);
@@ -37,8 +48,15 @@ QString FileAppender::fileName() const
}
+//! Sets the name of the file. The name can have no path, a relative path, or an absolute path.
+/**
+ * \sa fileName()
+ */
void FileAppender::setFileName(const QString& s)
{
+ if (s.isEmpty())
+ std::cerr << "<FileAppender::FileAppender> File name is empty. The appender will do nothing" << std::endl;
+
QMutexLocker locker(&m_logFileMutex);
if (m_logFile.isOpen())
m_logFile.close();
@@ -47,37 +65,50 @@ void FileAppender::setFileName(const QString& s)
}
+bool FileAppender::reopenFile()
+{
+ closeFile();
+ return openFile();
+}
+
+
bool FileAppender::openFile()
{
- bool isOpen = false;
- if (!m_logFile.isOpen())
+ if (m_logFile.fileName().isEmpty())
+ return false;
+
+ bool isOpen = m_logFile.isOpen();
+ if (!isOpen)
{
- if (m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
- {
+ isOpen = m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
+ if (isOpen)
m_logStream.setDevice(&m_logFile);
- isOpen = true;
- }
else
- {
std::cerr << "<FileAppender::append> Cannot open the log file " << qPrintable(m_logFile.fileName()) << std::endl;
- }
}
return isOpen;
}
+//! Write the log record to the file.
+/**
+ * \sa fileName()
+ * \sa AbstractStringAppender::format()
+ */
void FileAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
- const char* function, const QString& message)
+ const char* function, const QString& category, const QString& message)
{
QMutexLocker locker(&m_logFileMutex);
- openFile();
-
- m_logStream << formattedString(timeStamp, logLevel, file, line, function, message);
- m_logStream.flush();
- m_logFile.flush();
+ if (openFile())
+ {
+ m_logStream << formattedString(timeStamp, logLevel, file, line, function, category, message);
+ m_logStream.flush();
+ m_logFile.flush();
+ }
}
+
void FileAppender::closeFile()
{
QMutexLocker locker(&m_logFileMutex);
diff --git a/rbutil/rbutilqt/logger/src/Logger.cpp b/rbutil/rbutilqt/logger/src/Logger.cpp
new file mode 100644
index 0000000000..16a18db728
--- /dev/null
+++ b/rbutil/rbutilqt/logger/src/Logger.cpp
@@ -0,0 +1,1099 @@
+/*
+ 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 <QCoreApplication>
+#include <QReadWriteLock>
+#include <QSemaphore>
+#include <QDateTime>
+#include <QIODevice>
+#include <QTextCodec>
+
+#if defined(Q_OS_ANDROID)
+# include <android/log.h>
+# include <AndroidAppender.h>
+#endif
+
+// STL
+#include <iostream>
+
+
+/**
+ * \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 <QCoreApplication>
+ *
+ * #include <Logger.h>
+ * #include <ConsoleAppender.h>
+ *
+ * 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 <time> ms.
+ * \endcode
+ *
+ * If you are measuring a code of block execution time you may also add a name of block to the macro:
+ * \code
+ * int bar(bool doFoo)
+ * {
+ * LOG_TRACE_TIME();
+ *
+ * if (doFoo)
+ * {
+ * LOG_TRACE_TIME("Foo");
+ * ...
+ * }
+ *
+ * ...
+ * }
+ * // Outputs:
+ * // "Foo" finished in <time1> ms.
+ * // Function bar finished in <time2> ms.
+ * \endcode
+ *
+ * \note Macro switches to logging the seconds instead of milliseconds when the execution time reaches 10000 ms.
+ * \sa LOG_DEBUG_TIME, LOG_INFO_TIME
+ */
+
+
+/**
+ * \def LOG_DEBUG_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::Debug
+ * level log record. It works similar to LOG_TRACE_TIME() macro.
+ *
+ * \sa LOG_TRACE_TIME
+ */
+
+
+/**
+ * \def LOG_INFO_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::Info
+ * level log record. It works similar to LOG_TRACE_TIME() macro.
+ *
+ * \sa LOG_TRACE_TIME
+ */
+
+
+/**
+ * \class Logger
+ *
+ * \brief Very simple but rather powerful component which may be used for logging your application activities.
+ *
+ * Global logger instance created on a first access to it (e.g. registering appenders, calling a LOG_DEBUG() macro
+ * etc.) registers itself as a Qt default message handler and captures all the qDebug/qWarning/qCritical output.
+ *
+ * \note Qt 4 qDebug set of macro doesn't support capturing source function name, file name or line number so we
+ * recommend to use LOG_DEBUG() and other Logger macros instead.
+ *
+ * \sa cuteLogger
+ * \sa [CuteLogger Documentation](index.html)
+ */
+
+// Forward declarations
+static void cleanupLoggerGlobalInstance();
+
+#if QT_VERSION >= 0x050000
+static void qtLoggerMessageHandler(QtMsgType, const QMessageLogContext& context, const QString& msg);
+#else
+static void qtLoggerMessageHandler(QtMsgType type, const char* msg);
+#endif
+
+/**
+ * \internal
+ *
+ * LoggerPrivate class implements the Singleton pattern in a thread-safe way. It contains a static pointer to the
+ * global logger instance protected by QReadWriteLock
+ */
+class LoggerPrivate
+{
+ public:
+ static Logger* globalInstance;
+ static QReadWriteLock globalInstanceLock;
+
+ QList<AbstractAppender*> appenders;
+ QMutex loggerMutex;
+
+ QMap<QString, bool> categories;
+ QMultiMap<QString, AbstractAppender*> categoryAppenders;
+ QStringList noAppendersCategories; //<! Categories without appenders that was already warned about
+ QString defaultCategory;
+ bool writeDefaultCategoryToGlobalInstance;
+};
+
+
+// Static fields initialization
+Logger* LoggerPrivate::globalInstance = nullptr;
+QReadWriteLock LoggerPrivate::globalInstanceLock;
+
+
+static void cleanupLoggerGlobalInstance()
+{
+ QWriteLocker locker(&LoggerPrivate::globalInstanceLock);
+
+ delete LoggerPrivate::globalInstance;
+ LoggerPrivate::globalInstance = nullptr;
+}
+
+
+#if QT_VERSION >= 0x050000
+static void qtLoggerMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
+{
+ Logger::LogLevel level = Logger::Debug;
+ switch (type)
+ {
+ case QtDebugMsg:
+ level = Logger::Debug;
+ break;
+#if QT_VERSION >= 0x050500
+ case QtInfoMsg:
+ level = Logger::Info;
+ break;
+#endif
+ case QtWarningMsg:
+ level = Logger::Warning;
+ break;
+ case QtCriticalMsg:
+ level = Logger::Error;
+ break;
+ case QtFatalMsg:
+ level = Logger::Fatal;
+ break;
+ }
+
+ bool isDefaultCategory = QString::fromLatin1(context.category) == "default";
+ Logger::globalInstance()->write(level, context.file, context.line, context.function, isDefaultCategory ? nullptr : context.category, msg);
+}
+
+#else
+
+static void qtLoggerMessageHandler(QtMsgType type, const char* msg)
+{
+ switch (type)
+ {
+ case QtDebugMsg:
+ cuteLoggerInstance()->write(Logger::Debug, "", 0, "qDebug", 0, msg);
+ break;
+ case QtWarningMsg:
+ cuteLoggerInstance()->write(Logger::Warning, "", 0, "qDebug", 0, msg);
+ break;
+ case QtCriticalMsg:
+ cuteLoggerInstance()->write(Logger::Error, "", 0, "qDebug", 0, msg);
+ break;
+ case QtFatalMsg:
+ cuteLoggerInstance()->write(Logger::Fatal, "", 0, "qDebug", 0, msg);
+ break;
+ }
+}
+#endif
+
+
+//! Construct the instance of Logger
+/**
+ * If you're only using one global instance of logger you wouldn't probably need to use this constructor manually.
+ * Consider using [cuteLogger](@ref cuteLogger) macro instead to access the logger instance
+ */
+Logger::Logger()
+ : d_ptr(new LoggerPrivate)
+{
+ Q_D(Logger);
+ d->writeDefaultCategoryToGlobalInstance = false;
+}
+
+
+//! Construct the instance of Logger and set logger default category
+/**
+ * If you're only using one global instance of logger you wouldn't probably need to use this constructor manually.
+ * Consider using [cuteLogger](@ref cuteLogger) macro instead to access the logger instance and call
+ * [setDefaultCategory](@ref setDefaultCategory) method.
+ *
+ * \sa Logger()
+ * \sa setDefaultCategory()
+ */
+Logger::Logger(const QString& defaultCategory, bool writeToGlobalInstance)
+ : d_ptr(new LoggerPrivate)
+{
+ Q_D(Logger);
+ d->writeDefaultCategoryToGlobalInstance = writeToGlobalInstance;
+
+ setDefaultCategory(defaultCategory);
+}
+
+
+//! Destroy the instance of Logger
+/**
+ * You probably wouldn't need to use this function directly. Global instance of logger will be destroyed automatically
+ * at the end of your QCoreApplication execution
+ */
+Logger::~Logger()
+{
+ Q_D(Logger);
+
+ // Cleanup appenders
+ QMutexLocker appendersLocker(&d->loggerMutex);
+ QSet<AbstractAppender*> deleteList(QSet<AbstractAppender*>::fromList(d->appenders));
+ deleteList.unite(QSet<AbstractAppender*>::fromList(d->categoryAppenders.values()));
+ qDeleteAll(deleteList);
+
+ appendersLocker.unlock();
+
+ delete d_ptr;
+}
+
+
+//! Converts the LogLevel enum value to its string representation
+/**
+ * \param logLevel Log level to convert
+ *
+ * \sa LogLevel
+ * \sa levelFromString()
+ */
+QString Logger::levelToString(Logger::LogLevel logLevel)
+{
+ switch (logLevel)
+ {
+ case Trace:
+ return QLatin1String("Trace");
+ case Debug:
+ return QLatin1String("Debug");
+ case Info:
+ return QLatin1String("Info");
+ case Warning:
+ return QLatin1String("Warning");
+ case Error:
+ return QLatin1String("Error");
+ case Fatal:
+ return QLatin1String("Fatal");
+ }
+
+ return QString();
+}
+
+
+//! Converts the LogLevel string representation to enum value
+/**
+ * Comparation of the strings is case independent. If the log level string provided cannot be understood
+ * Logger::Debug is returned.
+ *
+ * \param s String to be decoded
+ *
+ * \sa LogLevel
+ * \sa levelToString()
+ */
+Logger::LogLevel Logger::levelFromString(const QString& s)
+{
+ QString str = s.trimmed().toLower();
+
+ LogLevel result = Debug;
+
+ if (str == QLatin1String("trace"))
+ result = Trace;
+ else if (str == QLatin1String("debug"))
+ result = Debug;
+ else if (str == QLatin1String("info"))
+ result = Info;
+ else if (str == QLatin1String("warning"))
+ result = Warning;
+ else if (str == QLatin1String("error"))
+ result = Error;
+ else if (str == QLatin1String("fatal"))
+ result = Fatal;
+
+ return result;
+}
+
+
+//! Returns the global instance of Logger
+/**
+ * In a most cases you shouldn't use this function directly. Consider using [cuteLogger](@ref cuteLogger) macro instead.
+ *
+ * \sa cuteLogger
+ */
+Logger* Logger::globalInstance()
+{
+ Logger* result = nullptr;
+ {
+ QReadLocker locker(&LoggerPrivate::globalInstanceLock);
+ result = LoggerPrivate::globalInstance;
+ }
+
+ if (!result)
+ {
+ QWriteLocker locker(&LoggerPrivate::globalInstanceLock);
+ LoggerPrivate::globalInstance = new Logger;
+
+#if QT_VERSION >= 0x050000
+ qInstallMessageHandler(qtLoggerMessageHandler);
+#else
+ qInstallMsgHandler(qtLoggerMessageHandler);
+#endif
+ qAddPostRoutine(cleanupLoggerGlobalInstance);
+ result = LoggerPrivate::globalInstance;
+ }
+
+ return result;
+}
+
+
+//! Registers the appender to write the log records to
+/**
+ * On the log writing call (using one of the macros or the write() function) Logger traverses through the list of
+ * the appenders and writes a log records to the each of them. Please, look through the AbstractAppender
+ * documentation to understand the concept of appenders.
+ *
+ * If no appenders was added to Logger, it falls back to logging into the \c std::cerr STL stream.
+ *
+ * \param appender Appender to register in the Logger
+ *
+ * \note Logger takes ownership on the appender and it will delete it on the application exit. According to this,
+ * appenders must be created on heap to prevent double destruction of the appender.
+ *
+ * \sa registerCategoryAppender
+ * \sa AbstractAppender
+ */
+void Logger::registerAppender(AbstractAppender* appender)
+{
+ Q_D(Logger);
+
+ QMutexLocker locker(&d->loggerMutex);
+
+ if (!d->appenders.contains(appender))
+ d->appenders.append(appender);
+ else
+ std::cerr << "Trying to register appender that was already registered" << std::endl;
+}
+
+//! Registers the appender to write the log records to the specific category
+/**
+ * Calling this method, you can link some appender with the named category.
+ * On the log writing call to the specific category (calling write() with category parameter directly,
+ * writing to the default category, or using special LOG_CDEBUG(), LOG_CWARNING() etc. macros),
+ * Logger writes the log message only to the list of registered category appenders.
+ *
+ * You can call logToGlobalInstance() to pass all category log messages to the global logger instance appenders
+ * (registered using registerAppender()).
+ * If no category appenders with specific name was registered to the Logger,
+ * it falls back to logging into the \c std::cerr STL stream, both with simple warning message.
+ *
+ * \param category Category name
+ * \param appender Appender to register in the Logger
+ *
+ * \note Logger takes ownership on the appender and it will delete it on the application exit. According to this,
+ * appenders must be created on heap to prevent double destruction of the appender.
+ *
+ * \sa registerAppender
+ * \sa LOG_CTRACE(), LOG_CDEBUG(), LOG_CINFO(), LOG_CWARNING(), LOG_CERROR(), LOG_CFATAL()
+ * \sa LOG_CATEGORY(), LOG_GLOBAL_CATEGORY()
+ * \sa logToGlobalInstance
+ * \sa setDefaultCategory
+ */
+void Logger::registerCategoryAppender(const QString& category, AbstractAppender* appender)
+{
+ Q_D(Logger);
+
+ QMutexLocker locker(&d->loggerMutex);
+
+ if (!d->categoryAppenders.values().contains(appender))
+ d->categoryAppenders.insert(category, appender);
+ else
+ std::cerr << "Trying to register appender that was already registered" << std::endl;
+}
+
+
+//! Removes the registered appender from logger
+/**
+ * After calling this function logger stops writing any of the records to the appender.
+ *
+ * \param appender Pointer to appender to remove from logger
+ * \note Removed appender will not be deleted on the application shutdown and you will need to destroy the object
+ * yourself.
+ * \sa registerAppender
+ */
+void Logger::removeAppender(AbstractAppender* appender)
+{
+ Q_D(Logger);
+
+ QMutexLocker locker(&d->loggerMutex);
+
+ d->appenders.removeAll(appender);
+ for (QMultiMap<QString,AbstractAppender*>::iterator it = d->categoryAppenders.begin(); it != d->categoryAppenders.end();)
+ {
+ if (it.value() == appender)
+ it = d->categoryAppenders.erase(it);
+ else
+ ++it;
+ }
+}
+
+
+//! Sets default logging category
+/**
+ * All log messages to this category appenders will also be written to general logger instance appenders (registered
+ * using [registerAppender](@ref registerAppender) method), and vice versa.
+ * In particular, any calls to the LOG_DEBUG() macro will be treated as category logging,
+ * so you needn't to specify category name using LOG_CDEBUG() macro.
+ *
+ * To unset the default category, pass a null string as a parameter.
+ *
+ * \param category Category name
+ *
+ * \note "category" format marker will be set to the category name for all of these messages
+ * (see [AbstractStringAppender::setFormat](@ref AbstractStringAppender::setFormat)).
+ *
+ * \sa defaultCategory()
+ * \sa registerCategoryAppender()
+ * \sa logToGlobalInstance()
+ */
+void Logger::setDefaultCategory(const QString& category)
+{
+ Q_D(Logger);
+
+ QMutexLocker locker(&d->loggerMutex);
+
+ d->defaultCategory = category;
+}
+
+//! Returns default logging category name
+/**
+ * \sa setDefaultCategory
+ */
+QString Logger::defaultCategory() const
+{
+ Q_D(const Logger);
+ return d->defaultCategory;
+}
+
+//! Links some logging category with the global logger instance appenders.
+/**
+ * If set to true, all log messages to the specified category appenders will also be written to the global logger instance appenders,
+ * registered using registerAppender().
+ *
+ * By default, all messages to the specific category are written only to the specific category appenders
+ * (registered using registerCategoryAppender()).
+ *
+ * \param category Category name
+ * \param logToGlobal Link or onlink the category from global logger instance appender
+ *
+ * \sa globalInstance
+ * \sa registerAppender
+ * \sa registerCategoryAppender
+ */
+void Logger::logToGlobalInstance(const QString& category, bool logToGlobal)
+{
+ Q_D(Logger);
+
+ if (this == globalInstance())
+ {
+ QMutexLocker locker(&d->loggerMutex);
+ d->categories.insert(category, logToGlobal);
+ }
+ else
+ {
+ globalInstance()->logToGlobalInstance(category, logToGlobal);
+ }
+}
+
+
+void Logger::write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, const char* category,
+ const QString& message, bool fromLocalInstance)
+{
+ Q_D(Logger);
+
+ QMutexLocker locker(&d->loggerMutex);
+
+ QString logCategory = QString::fromLatin1(category);
+ if (logCategory.isNull() && !d->defaultCategory.isNull())
+ logCategory = d->defaultCategory;
+
+ bool wasWritten = false;
+ bool isGlobalInstance = this == globalInstance();
+ bool linkedToGlobal = isGlobalInstance && d->categories.value(logCategory, false);
+
+ if (!logCategory.isNull())
+ {
+ QList<AbstractAppender*> appenders = d->categoryAppenders.values(logCategory);
+ if (appenders.length() == 0)
+ {
+ if (logCategory != d->defaultCategory && !linkedToGlobal && !fromLocalInstance && !d->noAppendersCategories.contains(logCategory))
+ {
+ std::cerr << "No appenders associated with category " << qPrintable(logCategory) << std::endl;
+ d->noAppendersCategories.append(logCategory);
+ }
+ }
+ else
+ {
+ foreach (AbstractAppender* appender, appenders)
+ appender->write(timeStamp, logLevel, file, line, function, logCategory, message);
+ wasWritten = true;
+ }
+ }
+
+ // the default category is linked to the main logger appenders
+ // global logger instance also writes all linked categories to the main appenders
+ if (logCategory.isNull() || logCategory == d->defaultCategory || linkedToGlobal)
+ {
+ if (!d->appenders.isEmpty())
+ {
+ foreach (AbstractAppender* appender, d->appenders)
+ appender->write(timeStamp, logLevel, file, line, function, logCategory, message);
+ wasWritten = true;
+ }
+ else
+ {
+ static bool noAppendersWarningShown = false;
+ if (!noAppendersWarningShown)
+ {
+#if defined(Q_OS_ANDROID)
+ __android_log_write(ANDROID_LOG_WARN, "Logger", "No appenders registered with logger");
+#else
+ std::cerr << "No appenders registered with logger" << std::endl;
+#endif
+ noAppendersWarningShown = true;
+ }
+ }
+ }
+
+ // local logger instances send category messages to the global instance
+ if (!isGlobalInstance)
+ {
+ if (!logCategory.isNull())
+ {
+ globalInstance()->write(timeStamp, logLevel, file, line, function, logCategory.toLatin1(), message, true);
+ wasWritten = true;
+ }
+
+ if (d->writeDefaultCategoryToGlobalInstance && logCategory == d->defaultCategory)
+ {
+ globalInstance()->write(timeStamp, logLevel, file, line, function, nullptr, message, true);
+ wasWritten = true;
+ }
+ }
+
+ if (!wasWritten && !fromLocalInstance)
+ {
+ // Fallback
+#if defined(Q_OS_ANDROID)
+ QString result = QString(QLatin1String("<%2> %3")).arg(AbstractStringAppender::stripFunctionName(function)).arg(message);
+ __android_log_write(AndroidAppender::androidLogPriority(logLevel), "Logger", qPrintable(result));
+#else
+ QString result = QString(QLatin1String("[%1] <%2> %3")).arg(levelToString(logLevel), -7)
+ .arg(AbstractStringAppender::stripFunctionName(function)).arg(message);
+ std::cerr << qPrintable(result) << std::endl;
+#endif
+ }
+
+ if (logLevel == Logger::Fatal)
+ abort();
+}
+
+
+//! Writes the log record
+/**
+ * Writes the log records with the supplied arguments to all the registered appenders.
+ *
+ * \note It is not recommended to call this function directly. Instead of this you can just call one of the macros
+ * (LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_FATAL) that will supply all the needed
+ * information to this function.
+ *
+ * \param timeStamp - the time stamp of the record
+ * \param logLevel - the log level of the record
+ * \param file - the name of the source file that requested the log record
+ * \param line - the line of the code of source file that requested the log record
+ * \param function - name of the function that requested the log record
+ * \param category - logging category (0 for default category)
+ * \param message - log message
+ *
+ * \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 LogLevel
+ * \sa LOG_TRACE, LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_FATAL
+ * \sa AbstractAppender
+ */
+void Logger::write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, const char* category,
+ const QString& message)
+{
+ write(timeStamp, logLevel, file, line, function, category, message, /* fromLocalInstance = */ false);
+}
+
+/**
+ * This is the overloaded function provided for the convinience. It behaves similar to the above function.
+ *
+ * This function uses the current timestamp obtained with \c QDateTime::currentDateTime().
+ *
+ * \sa write()
+ */
+void Logger::write(LogLevel logLevel, const char* file, int line, const char* function, const char* category,
+ const QString& message)
+{
+ write(QDateTime::currentDateTime(), logLevel, file, line, function, category, message);
+}
+
+
+//! Writes the assertion
+/**
+ * This function writes the assertion record using the write() function.
+ *
+ * The assertion record is always written using the Logger::Fatal log level which leads to the abortation of the
+ * program and generation of the core dump (if supported).
+ *
+ * The message written to the appenders will be identical to the \c condition argument prefixed with the
+ * <tt>ASSERT:</tt> notification.
+ *
+ * \note It is not recommended to call this function directly. Instead of this you can just call the LOG_ASSERT
+ * macro that will supply all the needed information to this function.
+ *
+ * \sa LOG_ASSERT
+ * \sa write()
+ */
+void Logger::writeAssert(const char* file, int line, const char* function, const char* condition)
+{
+ write(Logger::Fatal, file, line, function, nullptr, QString("ASSERT: \"%1\"").arg(condition));
+}
+
+
+Logger* cuteLoggerInstance()
+{
+ return Logger::globalInstance();
+}
+
+
+
+void LoggerTimingHelper::start(const char* msg, ...)
+{
+ va_list va;
+ va_start(va, msg);
+ m_block = QString().vsprintf(msg, va);
+ va_end(va);
+
+ m_time.start();
+}
+
+
+void LoggerTimingHelper::start(const QString& block)
+{
+ m_block = block;
+ m_time.start();
+}
+
+
+void LoggerTimingHelper::start(Logger::TimingMode mode, const QString& block)
+{
+ m_timingMode = mode;
+ m_block = block;
+ m_time.start();
+}
+
+
+LoggerTimingHelper::~LoggerTimingHelper()
+{
+ QString message;
+ if (m_block.isEmpty())
+ message = QString(QLatin1String("Function %1 finished in ")).arg(AbstractStringAppender::stripFunctionName(m_function));
+ else
+ message = QString(QLatin1String("\"%1\" finished in ")).arg(m_block);
+
+ int elapsed = m_time.elapsed();
+ if (elapsed >= 10000 && m_timingMode == Logger::TimingAuto)
+ message += QString(QLatin1String("%1 s.")).arg(elapsed / 1000);
+ else
+ message += QString(QLatin1String("%1 ms.")).arg(elapsed);
+
+ m_logger->write(m_logLevel, m_file, m_line, m_function, nullptr, message);
+}
+
+
+CuteMessageLogger::~CuteMessageLogger()
+{
+ m_l->write(m_level, m_file, m_line, m_function, m_category, m_message);
+}
+
+void CuteMessageLogger::write(const char* msg, ...)
+{
+ va_list va;
+ va_start(va, msg);
+ m_message = QString::vasprintf(msg, va);
+ va_end(va);
+}
+
+
+void CuteMessageLogger::write(const QString& msg)
+{
+ m_message = msg;
+}
+
+
+QDebug CuteMessageLogger::write()
+{
+ QDebug d(&m_message);
+ return d;
+}
diff --git a/rbutil/rbutilqt/logger/OutputDebugAppender.cpp b/rbutil/rbutilqt/logger/src/OutputDebugAppender.cpp
index 2d7facbd98..44d640512f 100644
--- a/rbutil/rbutilqt/logger/OutputDebugAppender.cpp
+++ b/rbutil/rbutilqt/logger/src/OutputDebugAppender.cpp
@@ -18,14 +18,26 @@
#include <windows.h>
+/**
+ * \class OutputDebugAppender
+ *
+ * \brief Appender that writes the log records to the Microsoft Debug Log
+ */
+
+
+//! Writes the log record to the windows debug log.
+/**
+ * \sa AbstractStringAppender::format()
+ */
void OutputDebugAppender::append(const QDateTime& timeStamp,
Logger::LogLevel logLevel,
const char* file,
int line,
const char* function,
+ const QString& category,
const QString& message)
{
- QString s = formattedString(timeStamp, logLevel, file, line, function, message);
+ QString s = formattedString(timeStamp, logLevel, file, line, function, category, message);
OutputDebugStringW((LPCWSTR) s.utf16());
}
diff --git a/rbutil/rbutilqt/main.cpp b/rbutil/rbutilqt/main.cpp
index cac93395fe..160a31ba0e 100644
--- a/rbutil/rbutilqt/main.cpp
+++ b/rbutil/rbutilqt/main.cpp
@@ -40,14 +40,14 @@ Q_IMPORT_PLUGIN(AccessibleFactory)
int main( int argc, char ** argv ) {
QApplication app( argc, argv );
ConsoleAppender* consoleAppender = new ConsoleAppender();
- consoleAppender->setFormat("[%f:%i %L] %m\n");
- Logger::registerAppender(consoleAppender);
+ consoleAppender->setFormat("[%{file}:%{line} %{type}] %{message}\n");
+ cuteLoggerInstance()->registerAppender(consoleAppender);
SysTrace::rotateTrace();
QString tracefile = QDir::tempPath() + "/rbutil-trace.log";
FileAppender* fileAppender = new FileAppender();
- fileAppender->setFormat("[%f:%i %L] %m\n");
+ fileAppender->setFormat("[%{file}:%{line} %{type}] %{message}\n");
fileAppender->setFileName(tracefile);
- Logger::registerAppender(fileAppender);
+ cuteLoggerInstance()->registerAppender(fileAppender);
LOG_INFO() << "Starting trace at" << QDateTime::currentDateTime().toString(Qt::ISODate);
#if defined(Q_OS_MAC)
diff --git a/rbutil/rbutilqt/systrace.cpp b/rbutil/rbutilqt/systrace.cpp
index 83f70b3da5..5f3450eae8 100644
--- a/rbutil/rbutilqt/systrace.cpp
+++ b/rbutil/rbutilqt/systrace.cpp
@@ -50,11 +50,11 @@ void SysTrace::refresh(void)
QString color;
while(!c.atEnd()) {
line = c.readLine();
- if(line.contains("WARNING"))
+ if(line.contains("Warning"))
color = "orange";
- else if(line.contains("ERROR"))
+ else if(line.contains("Error"))
color = "red";
- else if(line.contains("DEBUG"))
+ else if(line.contains("Debug"))
color = "blue";
#if 0
else if(line.contains("INFO"))