Add logger

Change-Id: I4ae4e2d77d137646b312b2c6124dd6ab2653936e
This commit is contained in:
杨万青 2015-09-25 17:21:53 +08:00
parent d65a3bf904
commit 593b20d5c1
Notes: Deepin Code Review 2016-06-14 07:19:47 +00:00
Verified+1: Anonymous Coward #1000004
Code-Review+2: <mr.asianwang@gmail.com>
Submitted-by: <mr.asianwang@gmail.com>
Submitted-at: Fri, 25 Sep 2015 19:57:55 +0800
Reviewed-on: https://cr.deepin.io/7406
Project: dde/dde-dock
Branch: refs/heads/master
20 changed files with 2797 additions and 1 deletions

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,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,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) {
register 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('/', -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,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

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

@ -0,0 +1,36 @@
/*
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 CONSOLEAPPENDER_H
#define CONSOLEAPPENDER_H
#include "CuteLogger_global.h"
#include <AbstractStringAppender.h>
class CUTELOGGERSHARED_EXPORT ConsoleAppender : public AbstractStringAppender
{
public:
ConsoleAppender();
virtual QString format() const;
void ignoreEnvironmentPattern(bool ignore);
protected:
virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
const char* function, const QString& category, const QString& message);
private:
bool m_ignoreEnvPattern;
};
#endif // CONSOLEAPPENDER_H

View File

@ -0,0 +1,16 @@
#ifndef CUTELOGGER_GLOBAL_H
#define CUTELOGGER_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(CUTELOGGER_LIBRARY)
# define CUTELOGGERSHARED_EXPORT Q_DECL_EXPORT
#else
#if defined(Q_OS_WIN32)
# define CUTELOGGERSHARED_EXPORT
#else
# define CUTELOGGERSHARED_EXPORT Q_DECL_IMPORT
#endif
#endif
#endif // CUTELOGGER_GLOBAL_H

103
cutelogger/FileAppender.cpp Normal file
View File

@ -0,0 +1,103 @@
/*
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 "FileAppender.h"
// 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);
}
FileAppender::~FileAppender()
{
closeFile();
}
//! Returns the name set by setFileName() or to the FileAppender constructor.
/**
* \sa setFileName()
*/
QString FileAppender::fileName() const
{
QMutexLocker locker(&m_logFileMutex);
return m_logFile.fileName();
}
//! 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)
{
QMutexLocker locker(&m_logFileMutex);
if (m_logFile.isOpen())
m_logFile.close();
m_logFile.setFileName(s);
}
bool FileAppender::openFile()
{
bool isOpen = m_logFile.isOpen();
if (!isOpen)
{
isOpen = m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text);
if (isOpen)
m_logStream.setDevice(&m_logFile);
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& category, const QString& message)
{
QMutexLocker locker(&m_logFileMutex);
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);
m_logFile.close();
}

47
cutelogger/FileAppender.h Normal file
View File

@ -0,0 +1,47 @@
/*
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 FILEAPPENDER_H
#define FILEAPPENDER_H
// Logger
#include "CuteLogger_global.h"
#include <AbstractStringAppender.h>
// Qt
#include <QFile>
#include <QTextStream>
class CUTELOGGERSHARED_EXPORT FileAppender : public AbstractStringAppender
{
public:
FileAppender(const QString& fileName = QString());
~FileAppender();
QString fileName() const;
void setFileName(const QString&);
protected:
virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
const char* function, const QString& category, const QString& message);
bool openFile();
void closeFile();
private:
QFile m_logFile;
QTextStream m_logStream;
mutable QMutex m_logFileMutex;
};
#endif // FILEAPPENDER_H

1104
cutelogger/Logger.cpp Normal file

File diff suppressed because it is too large Load Diff

206
cutelogger/Logger.h Normal file
View File

@ -0,0 +1,206 @@
/*
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* loggerInstance();
#define logger loggerInstance()
#define LOG_TRACE CuteMessageLogger(loggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO).write
#define LOG_DEBUG CuteMessageLogger(loggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO).write
#define LOG_INFO CuteMessageLogger(loggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO).write
#define LOG_WARNING CuteMessageLogger(loggerInstance(), Logger::Warning, __FILE__, __LINE__, Q_FUNC_INFO).write
#define LOG_ERROR CuteMessageLogger(loggerInstance(), Logger::Error, __FILE__, __LINE__, Q_FUNC_INFO).write
#define LOG_FATAL CuteMessageLogger(loggerInstance(), Logger::Fatal, __FILE__, __LINE__, Q_FUNC_INFO).write
#define LOG_CTRACE(category) CuteMessageLogger(loggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO, category).write()
#define LOG_CDEBUG(category) CuteMessageLogger(loggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO, category).write()
#define LOG_CINFO(category) CuteMessageLogger(loggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO, category).write()
#define LOG_CWARNING(category) CuteMessageLogger(loggerInstance(), Logger::Warning, __FILE__, __LINE__, Q_FUNC_INFO, category).write()
#define LOG_CERROR(category) CuteMessageLogger(loggerInstance(), Logger::Error, __FILE__, __LINE__, Q_FUNC_INFO, category).write()
#define LOG_CFATAL(category) CuteMessageLogger(loggerInstance(), Logger::Fatal, __FILE__, __LINE__, Q_FUNC_INFO, category).write()
#define LOG_TRACE_TIME LoggerTimingHelper loggerTimingHelper(loggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start
#define LOG_DEBUG_TIME LoggerTimingHelper loggerTimingHelper(loggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start
#define LOG_INFO_TIME LoggerTimingHelper loggerTimingHelper(loggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start
#define LOG_ASSERT(cond) ((!(cond)) ? loggerInstance()->writeAssert(__FILE__, __LINE__, Q_FUNC_INFO, #cond) : qt_noop())
#define LOG_ASSERT_X(cond, msg) ((!(cond)) ? loggerInstance()->writeAssert(__FILE__, __LINE__, Q_FUNC_INFO, msg) : qt_noop())
#define LOG_CATEGORY(category) \
private:\
Logger* loggerInstance()\
{\
static Logger customLoggerInstance(category);\
return &customLoggerInstance;\
}\
#define LOG_GLOBAL_CATEGORY(category) \
private:\
Logger* loggerInstance()\
{\
static Logger customLoggerInstance(category);\
customLoggerInstance.logToGlobalInstance(category, true);\
return &customLoggerInstance;\
}\
class LoggerPrivate;
class CUTELOGGERSHARED_EXPORT Logger
{
Q_DISABLE_COPY(Logger)
public:
Logger();
Logger(const QString& defaultCategory);
~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.
};
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 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);
QDebug write(LogLevel logLevel, const char* file, int line, const char* function, const char* category);
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:
Q_DECL_CONSTEXPR 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(0)
{}
Q_DECL_CONSTEXPR 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)
{}
void write(const char* msg, ...) const
#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) const;
QDebug write() const;
private:
Logger* m_l;
Logger::LogLevel m_level;
const char* m_file;
int m_line;
const char* m_function;
const char* m_category;
};
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_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());
~LoggerTimingHelper();
private:
Logger* m_logger;
QTime m_time;
Logger::LogLevel m_logLevel;
const char* m_file;
int m_line;
const char* m_function;
QString m_block;
};
#endif // LOGGER_H

View File

@ -0,0 +1,43 @@
/*
Copyright (c) 2010 Karl-Heinz Reichel (khreichel at googlemail 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 "OutputDebugAppender.h"
// STL
#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, category, message);
OutputDebugStringW((LPCWSTR) s.utf16());
}

View File

@ -0,0 +1,29 @@
/*
Copyright (c) 2010 Karl-Heinz Reichel (khreichel at googlemail 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 OUTPUTDEBUGAPPENDER_H
#define OUTPUTDEBUGAPPENDER_H
#include "CuteLogger_global.h"
#include <AbstractStringAppender.h>
class CUTELOGGERSHARED_EXPORT OutputDebugAppender : public AbstractStringAppender
{
protected:
virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
const char* function, const QString& category, const QString& message);
};
#endif // OUTPUTDEBUGAPPENDER_H

View File

@ -0,0 +1,248 @@
#include <QDateTime>
#include <QDir>
#include <QFileInfo>
#include "RollingFileAppender.h"
RollingFileAppender::RollingFileAppender(const QString& fileName)
: FileAppender(fileName),
m_logFilesLimit(0)
{}
void RollingFileAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
const char* function, const QString& category, const QString& message)
{
if (!m_rollOverTime.isNull() && QDateTime::currentDateTime() > m_rollOverTime)
rollOver();
FileAppender::append(timeStamp, logLevel, file, line, function, category, message);
}
RollingFileAppender::DatePattern RollingFileAppender::datePattern() const
{
QMutexLocker locker(&m_rollingMutex);
return m_frequency;
}
QString RollingFileAppender::datePatternString() const
{
QMutexLocker locker(&m_rollingMutex);
return m_datePatternString;
}
void RollingFileAppender::setDatePattern(DatePattern datePattern)
{
switch (datePattern)
{
case MinutelyRollover:
setDatePatternString(QLatin1String("'.'yyyy-MM-dd-hh-mm"));
break;
case HourlyRollover:
setDatePatternString(QLatin1String("'.'yyyy-MM-dd-hh"));
break;
case HalfDailyRollover:
setDatePatternString(QLatin1String("'.'yyyy-MM-dd-a"));
break;
case DailyRollover:
setDatePatternString(QLatin1String("'.'yyyy-MM-dd"));
break;
case WeeklyRollover:
setDatePatternString(QLatin1String("'.'yyyy-ww"));
break;
case MonthlyRollover:
setDatePatternString(QLatin1String("'.'yyyy-MM"));
break;
default:
Q_ASSERT_X(false, "DailyRollingFileAppender::setDatePattern()", "Invalid datePattern constant");
setDatePattern(DailyRollover);
};
QMutexLocker locker(&m_rollingMutex);
m_frequency = datePattern;
computeRollOverTime();
}
void RollingFileAppender::setDatePattern(const QString& datePattern)
{
setDatePatternString(datePattern);
computeFrequency();
computeRollOverTime();
}
void RollingFileAppender::setDatePatternString(const QString& datePatternString)
{
QMutexLocker locker(&m_rollingMutex);
m_datePatternString = datePatternString;
}
void RollingFileAppender::computeFrequency()
{
QMutexLocker locker(&m_rollingMutex);
const QDateTime startTime(QDate(1999, 1, 1), QTime(0, 0));
const QString startString = startTime.toString(m_datePatternString);
if (startString != startTime.addSecs(60).toString(m_datePatternString))
m_frequency = MinutelyRollover;
else if (startString != startTime.addSecs(60 * 60).toString(m_datePatternString))
m_frequency = HourlyRollover;
else if (startString != startTime.addSecs(60 * 60 * 12).toString(m_datePatternString))
m_frequency = HalfDailyRollover;
else if (startString != startTime.addDays(1).toString(m_datePatternString))
m_frequency = DailyRollover;
else if (startString != startTime.addDays(7).toString(m_datePatternString))
m_frequency = WeeklyRollover;
else if (startString != startTime.addMonths(1).toString(m_datePatternString))
m_frequency = MonthlyRollover;
else
{
Q_ASSERT_X(false, "DailyRollingFileAppender::computeFrequency", "The pattern '%1' does not specify a frequency");
return;
}
}
void RollingFileAppender::removeOldFiles()
{
if (m_logFilesLimit <= 1)
return;
QFileInfo fileInfo(fileName());
QDir logDirectory(fileInfo.absoluteDir());
logDirectory.setFilter(QDir::Files);
logDirectory.setNameFilters(QStringList() << fileInfo.fileName() + "*");
QFileInfoList logFiles = logDirectory.entryInfoList();
QMap<QDateTime, QString> fileDates;
for (int i = 0; i < logFiles.length(); ++i)
{
QString name = logFiles[i].fileName();
QString suffix = name.mid(name.indexOf(fileInfo.fileName()) + fileInfo.fileName().length());
QDateTime fileDateTime = QDateTime::fromString(suffix, datePatternString());
if (fileDateTime.isValid())
fileDates.insert(fileDateTime, logFiles[i].absoluteFilePath());
}
QList<QString> fileDateNames = fileDates.values();
for (int i = 0; i < fileDateNames.length() - m_logFilesLimit + 1; ++i)
QFile::remove(fileDateNames[i]);
}
void RollingFileAppender::computeRollOverTime()
{
Q_ASSERT_X(!m_datePatternString.isEmpty(), "DailyRollingFileAppender::computeRollOverTime()", "No active date pattern");
QDateTime now = QDateTime::currentDateTime();
QDate nowDate = now.date();
QTime nowTime = now.time();
QDateTime start;
switch (m_frequency)
{
case MinutelyRollover:
{
start = QDateTime(nowDate, QTime(nowTime.hour(), nowTime.minute(), 0, 0));
m_rollOverTime = start.addSecs(60);
}
break;
case HourlyRollover:
{
start = QDateTime(nowDate, QTime(nowTime.hour(), 0, 0, 0));
m_rollOverTime = start.addSecs(60*60);
}
break;
case HalfDailyRollover:
{
int hour = nowTime.hour();
if (hour >= 12)
hour = 12;
else
hour = 0;
start = QDateTime(nowDate, QTime(hour, 0, 0, 0));
m_rollOverTime = start.addSecs(60*60*12);
}
break;
case DailyRollover:
{
start = QDateTime(nowDate, QTime(0, 0, 0, 0));
m_rollOverTime = start.addDays(1);
}
break;
case WeeklyRollover:
{
// Qt numbers the week days 1..7. The week starts on Monday.
// Change it to being numbered 0..6, starting with Sunday.
int day = nowDate.dayOfWeek();
if (day == Qt::Sunday)
day = 0;
start = QDateTime(nowDate, QTime(0, 0, 0, 0)).addDays(-1 * day);
m_rollOverTime = start.addDays(7);
}
break;
case MonthlyRollover:
{
start = QDateTime(QDate(nowDate.year(), nowDate.month(), 1), QTime(0, 0, 0, 0));
m_rollOverTime = start.addMonths(1);
}
break;
default:
Q_ASSERT_X(false, "DailyRollingFileAppender::computeInterval()", "Invalid datePattern constant");
m_rollOverTime = QDateTime::fromTime_t(0);
}
m_rollOverSuffix = start.toString(m_datePatternString);
Q_ASSERT_X(now.toString(m_datePatternString) == m_rollOverSuffix,
"DailyRollingFileAppender::computeRollOverTime()", "File name changes within interval");
Q_ASSERT_X(m_rollOverSuffix != m_rollOverTime.toString(m_datePatternString),
"DailyRollingFileAppender::computeRollOverTime()", "File name does not change with rollover");
}
void RollingFileAppender::rollOver()
{
Q_ASSERT_X(!m_datePatternString.isEmpty(), "DailyRollingFileAppender::rollOver()", "No active date pattern");
QString rollOverSuffix = m_rollOverSuffix;
computeRollOverTime();
if (rollOverSuffix == m_rollOverSuffix)
return;
closeFile();
QString targetFileName = fileName() + rollOverSuffix;
QFile f(targetFileName);
if (f.exists() && !f.remove())
return;
f.setFileName(fileName());
if (!f.rename(targetFileName))
return;
openFile();
removeOldFiles();
}
void RollingFileAppender::setLogFilesLimit(int limit)
{
QMutexLocker locker(&m_rollingMutex);
m_logFilesLimit = limit;
}
int RollingFileAppender::logFilesLimit() const
{
QMutexLocker locker(&m_rollingMutex);
return m_logFilesLimit;
}

View File

@ -0,0 +1,77 @@
#ifndef ROLLINGFILEAPPENDER_H
#define ROLLINGFILEAPPENDER_H
#include <QDateTime>
#include <FileAppender.h>
/*!
* \brief The RollingFileAppender class extends FileAppender so that the underlying file is rolled over at a user chosen frequency.
*
* The class is based on Log4Qt.DailyRollingFileAppender class (http://log4qt.sourceforge.net/)
* and has the same date pattern format.
*
* For example, if the fileName is set to /foo/bar and the DatePattern set to the daily rollover ('.'yyyy-MM-dd'.log'), on 2014-02-16 at midnight,
* the logging file /foo/bar.log will be copied to /foo/bar.2014-02-16.log and logging for 2014-02-17 will continue in /foo/bar
* until it rolls over the next day.
*
* The logFilesLimit parameter is used to automatically delete the oldest log files in the directory during rollover
* (so no more than logFilesLimit recent log files exist in the directory at any moment).
* \sa setDatePattern(DatePattern), setLogFilesLimit(int)
*/
class CUTELOGGERSHARED_EXPORT RollingFileAppender : public FileAppender
{
public:
/*!
* The enum DatePattern defines constants for date patterns.
* \sa setDatePattern(DatePattern)
*/
enum DatePattern
{
/*! The minutely date pattern string is "'.'yyyy-MM-dd-hh-mm". */
MinutelyRollover = 0,
/*! The hourly date pattern string is "'.'yyyy-MM-dd-hh". */
HourlyRollover,
/*! The half-daily date pattern string is "'.'yyyy-MM-dd-a". */
HalfDailyRollover,
/*! The daily date pattern string is "'.'yyyy-MM-dd". */
DailyRollover,
/*! The weekly date pattern string is "'.'yyyy-ww". */
WeeklyRollover,
/*! The monthly date pattern string is "'.'yyyy-MM". */
MonthlyRollover
};
Q_ENUMS(DatePattern)
RollingFileAppender(const QString& fileName = QString());
DatePattern datePattern() const;
void setDatePattern(DatePattern datePattern);
void setDatePattern(const QString& datePattern);
QString datePatternString() const;
void setLogFilesLimit(int limit);
int logFilesLimit() const;
protected:
virtual void append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
const char* function, const QString& category, const QString& message);
private:
void rollOver();
void computeRollOverTime();
void computeFrequency();
void removeOldFiles();
void setDatePatternString(const QString& datePatternString);
QString m_datePatternString;
DatePattern m_frequency;
QDateTime m_rollOverTime;
QString m_rollOverSuffix;
int m_logFilesLimit;
mutable QMutex m_rollingMutex;
};
#endif // ROLLINGFILEAPPENDER_H

25
cutelogger/cutelogger.pri Normal file
View File

@ -0,0 +1,25 @@
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/RollingFileAppender.h \
$$PWD/Logger.h \
$$PWD/FileAppender.h \
$$PWD/CuteLogger_global.h \
$$PWD/ConsoleAppender.h \
$$PWD/AbstractStringAppender.h \
$$PWD/AbstractAppender.h \
$$PWD/logmanager.h
SOURCES += \
$$PWD/RollingFileAppender.cpp \
$$PWD/Logger.cpp \
$$PWD/FileAppender.cpp \
$$PWD/ConsoleAppender.cpp \
$$PWD/AbstractStringAppender.cpp \
$$PWD/AbstractAppender.cpp \
$$PWD/logmanager.cpp
win32 {
SOURCES += $$PWD/OutputDebugAppender.cpp
HEADERS += $$PWD/OutputDebugAppender.h
}

51
cutelogger/logmanager.cpp Normal file
View File

@ -0,0 +1,51 @@
#include "logmanager.h"
#include <Logger.h>
#include <ConsoleAppender.h>
#include <RollingFileAppender.h>
LogManager::LogManager()
{
m_format = "%{time}{dd-MM-yyyy, HH:mm:ss.zzz} [%{type:-7}] [%{file:-25} %{line}] %{message}\n";
}
void LogManager::initConsoleAppender(){
m_consoleAppender = new ConsoleAppender;
m_consoleAppender->setFormat(m_format);
logger->registerAppender(m_consoleAppender);
}
void LogManager::initRollingFileAppender(){
QString cachePath = QStandardPaths::standardLocations(QStandardPaths::CacheLocation).at(0);
if (!QDir(cachePath).exists()){
QDir(cachePath).mkpath(cachePath);
}
m_logPath = joinPath(cachePath, QString("%1.log").arg(qApp->applicationName()));
m_rollingFileAppender = new RollingFileAppender(m_logPath);
m_rollingFileAppender->setFormat(m_format);
m_rollingFileAppender->setLogFilesLimit(5);
m_rollingFileAppender->setDatePattern(RollingFileAppender::DailyRollover);
logger->registerAppender(m_rollingFileAppender);
}
void LogManager::debug_log_console_on(){
#if !defined(QT_NO_DEBUG)
LogManager::instance()->initConsoleAppender();
#endif
LogManager::instance()->initRollingFileAppender();
}
QString LogManager::joinPath(const QString &path, const QString &fileName){
QString separator(QDir::separator());
return QString("%1%2%3").arg(path, separator, fileName);
}
QString LogManager::getlogFilePath(){
return m_logPath;
}
LogManager::~LogManager()
{
}

41
cutelogger/logmanager.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef LOGMANAGER_H
#define LOGMANAGER_H
#include <QtCore>
class ConsoleAppender;
class RollingFileAppender;
class LogManager
{
public:
void initConsoleAppender();
void initRollingFileAppender();
inline static LogManager* instance(){
static LogManager instance;
return &instance;
}
void debug_log_console_on();
QString joinPath(const QString& path, const QString& fileName);
QString getlogFilePath();
signals:
public slots:
private:
QString m_format;
QString m_logPath;
ConsoleAppender* m_consoleAppender;
RollingFileAppender* m_rollingFileAppender;
explicit LogManager();
~LogManager();
LogManager(const LogManager &);
LogManager & operator = (const LogManager &);
};
#endif // LOGMANAGER_H

View File

@ -28,7 +28,7 @@ headers.files += src/interfaces/dockconstants.h \
src/interfaces/dockplugininterface.h \
src/interfaces/dockpluginproxyinterface.h
headers.path = /usr/include/dde-dock
include (../cutelogger/cutelogger.pri)
INSTALLS += headers target
HEADERS += \

View File

@ -4,6 +4,8 @@
#include <QDBusConnection>
#include "mainwidget.h"
#include "logmanager.h"
#include "Logger.h"
// let startdde know that we've already started.
void RegisterDdeSession()
@ -29,6 +31,9 @@ int main(int argc, char *argv[])
a.setApplicationName("dde-dock");
a.setApplicationDisplayName("Dock");
LogManager::instance()->debug_log_console_on();
LOG_INFO() << LogManager::instance()->getlogFilePath();
if (QDBusConnection::sessionBus().registerService(DBUS_NAME)) {
QFile file("://qss/resources/dark/qss/dde-dock.qss");
if (file.open(QFile::ReadOnly)) {