rbutil: Update CuteLogger to most recent upstream.

Update to the most recent git version.

This changes the folder structure and renames some classes to follow
upstream.

Restore MSVC static link fix, and fix wrong variable in qmake project file.

Change-Id: I874bb9ed60e37af09a841988e771fd341414d145
This commit is contained in:
Dominik Riebeling 2020-06-08 21:13:11 +02:00
parent c425d4627e
commit 48d2927ecc
24 changed files with 2201 additions and 1242 deletions

View file

@ -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);
}
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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));
}

View file

@ -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);
}

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -17,16 +17,20 @@
#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

View file

@ -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();

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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()
*/

View file

@ -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;
}

View file

@ -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));
}

View file

@ -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,36 +65,49 @@ 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.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))
if (m_logFile.fileName().isEmpty())
return false;
bool isOpen = m_logFile.isOpen();
if (!isOpen)
{
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);
if (openFile())
{
m_logStream << formattedString(timeStamp, logLevel, file, line, function, category, message);
m_logStream.flush();
m_logFile.flush();
}
}
void FileAppender::closeFile()
{

File diff suppressed because it is too large Load diff

View file

@ -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());
}

View file

@ -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)

View file

@ -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"))