refactor: log files move to dtklog

Issue: linuxdeepin/dtk#182

dtklog: https://github.com/linuxdeepin/dtklog
This commit is contained in:
ck 2024-06-27 14:55:12 +08:00 committed by mike
parent 51feaf445c
commit 1a6e919cc5
31 changed files with 23 additions and 3353 deletions

5
debian/control vendored
View File

@ -5,7 +5,7 @@ Maintainer: Deepin Packages Builder <packages@deepin.com>
Build-Depends: debhelper-compat ( =12), pkg-config,
qttools5-dev-tools, qttools5-dev, qtbase5-private-dev, doxygen,
libgsettings-qt-dev, libgtest-dev, libdtkcommon-dev, cmake,
libuchardet-dev, libicu-dev, libsystemd-dev, libspdlog-dev
libuchardet-dev, libicu-dev, libdtklog-dev
Standards-Version: 3.9.8
Package: libdtkcore5
@ -28,7 +28,8 @@ Description: Deepin Tool Kit Core Utilities
Package: libdtkcore-dev
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libdtkcore5( =${binary:Version}), libdtkcommon-dev(>=5.6.16)
Depends: ${shlibs:Depends}, ${misc:Depends}, libdtkcore5( =${binary:Version}),
libdtkcommon-dev(>=5.6.16), libdtklog-dev
Description: Deepin Tool Kit Core Devel library
DtkCore is base devel library of Deepin Qt/C++ applications.
.

2
debian/rules vendored
View File

@ -22,7 +22,7 @@ endif
dh $@
override_dh_auto_configure:
dh_auto_configure -- -DBUILD_EXAMPLES=OFF -DBUILD_DOCS=ON -DBUILD_VERSION=$(BUILD_VER) -DDTK_VERSION=$(PACK_VER) -DD_DSG_APP_DATA_FALLBACK=/var/dsg/appdata -DBUILD_WITH_SYSTEMD=ON
dh_auto_configure -- -DBUILD_EXAMPLES=OFF -DBUILD_DOCS=ON -DBUILD_VERSION=$(BUILD_VER) -DDTK_VERSION=$(PACK_VER) -DD_DSG_APP_DATA_FALLBACK=/var/dsg/appdata
#override_dh_auto_test:
# echo "skip auto test"

View File

@ -1,9 +1,9 @@
#include "RollingFileAppender.h"
#include "Logger.h"
#include "LogManager.h"
#include "FileAppender.h"
#include "ConsoleAppender.h"
#include "AbstractStringAppender.h"
#include "AbstractAppender.h"
#include "JournalAppender.h"
#include "dloghelper.h"
#include <RollingFileAppender.h>
#include <Logger.h>
#include <LogManager.h>
#include <FileAppender.h>
#include <ConsoleAppender.h>
#include <AbstractStringAppender.h>
#include <AbstractAppender.h>
#include <JournalAppender.h>
#include <dloghelper.h>

View File

@ -1,40 +0,0 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#ifndef ABSTRACTAPPENDER_H
#define ABSTRACTAPPENDER_H
#include "dtkcore_global.h"
#include <Logger.h>
#include <QMutex>
DCORE_BEGIN_NAMESPACE
class LIBDTKCORESHARED_EXPORT AbstractAppender
{
public:
AbstractAppender();
virtual ~AbstractAppender();
Logger::LogLevel detailsLevel() const;
void setDetailsLevel(Logger::LogLevel level);
void setDetailsLevel(const QString &level);
void write(const QDateTime &time, Logger::LogLevel level, const char *file, int line,
const char *func, const QString &category, const QString &msg);
protected:
virtual void append(const QDateTime &time, Logger::LogLevel level, const char *file, int line,
const char *func, const QString &category, const QString &msg) = 0;
private:
QMutex m_writeMutex;
Logger::LogLevel m_detailsLevel;
mutable QMutex m_detailsLevelMutex;
};
DCORE_END_NAMESPACE
#endif // ABSTRACTAPPENDER_H

View File

@ -1,37 +0,0 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#ifndef ABSTRACTSTRINGAPPENDER_H
#define ABSTRACTSTRINGAPPENDER_H
#include "AbstractAppender.h"
#include <QReadWriteLock>
#include <QDateTime>
DCORE_BEGIN_NAMESPACE
class LIBDTKCORESHARED_EXPORT AbstractStringAppender : public AbstractAppender
{
public:
AbstractStringAppender();
virtual QString format() const;
void setFormat(const QString &format);
static QString stripFunctionName(const char *name);
protected:
QString formattedString(const QDateTime &time, Logger::LogLevel level, const char *file, int line,
const char *func, const QString &category, const QString &msg) const;
QString formattedString(const QDateTime &time, Logger::LogLevel level, const char *file, int line,
const char *func, const QString &category, const QString &msg, bool withcolor) const;
private:
static QByteArray qCleanupFuncinfo(const char*);
QString m_format;
mutable QReadWriteLock m_formatLock;
};
DCORE_END_NAMESPACE
#endif // ABSTRACTSTRINGAPPENDER_H

View File

@ -1,30 +0,0 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#ifndef CONSOLEAPPENDER_H
#define CONSOLEAPPENDER_H
#include "dtkcore_global.h"
#include <AbstractStringAppender.h>
DCORE_BEGIN_NAMESPACE
class LIBDTKCORESHARED_EXPORT ConsoleAppender : public AbstractStringAppender
{
public:
ConsoleAppender();
virtual QString format() const;
void ignoreEnvironmentPattern(bool ignore);
protected:
virtual void append(const QDateTime &time, Logger::LogLevel level, const char *file, int line,
const char *func, const QString &category, const QString &msg);
private:
bool m_ignoreEnvPattern;
};
DCORE_END_NAMESPACE
#endif // CONSOLEAPPENDER_H

View File

@ -1,43 +0,0 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#ifndef FILEAPPENDER_H
#define FILEAPPENDER_H
// Logger
#include "dtkcore_global.h"
#include <AbstractStringAppender.h>
// Qt
#include <QFile>
#include <QTextStream>
DCORE_BEGIN_NAMESPACE
class LIBDTKCORESHARED_EXPORT FileAppender : public AbstractStringAppender
{
public:
FileAppender(const QString &fileName = QString());
~FileAppender();
QString fileName() const;
void setFileName(const QString &s);
qint64 size() const;
protected:
virtual void append(const QDateTime &time, Logger::LogLevel level, const char *file, int line,
const char *func, const QString &category, const QString &msg);
bool openFile();
void closeFile();
private:
QFile m_logFile;
QTextStream m_logStream;
mutable QMutex m_logFileMutex;
};
DCORE_END_NAMESPACE
#endif // FILEAPPENDER_H

View File

@ -1,38 +0,0 @@
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#ifndef JOURNALAPPENDER_H
#define JOURNALAPPENDER_H
#include "dtkcore_global.h"
#include <AbstractAppender.h>
DCORE_BEGIN_NAMESPACE
class LIBDTKCORESHARED_EXPORT JournalAppender : public AbstractAppender
{
public:
JournalAppender()
: AbstractAppender()
{
}
~JournalAppender() override = default;
using JournalPriority = int;
protected:
virtual void append(const QDateTime &time,
Logger::LogLevel level,
const char *file,
int line,
const char *func,
const QString &category,
const QString &msg) override;
private:
bool m_ignoreEnvPattern;
};
DCORE_END_NAMESPACE
#endif // JOURNALAPPENDER_H

View File

@ -1,66 +0,0 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#ifndef LOGGER_H
#define LOGGER_H
#include <QString>
#include <QDebug>
#include <QDateTime>
#include "dloggerdefs.h"
DCORE_BEGIN_NAMESPACE
class AbstractAppender;
class LoggerPrivate;
class LIBDTKCORESHARED_EXPORT Logger
{
Q_DISABLE_COPY(Logger)
public:
//!@~english the log levels
enum LogLevel {
Trace, //!<@~english Trace level. Can be used for mostly unneeded records used for internal code tracing.
Debug, //!<@~english Debug level.for the debugging of the software.
Info, //!<@~english Info level. Can be used for informational records, which may be interesting for not only developers.
Warning, //!<@~english Warning. May be used to log some non-fatal warnings detected by your application.
Error, //!<@~english May be used for a big problems making your application work wrong but not crashing.
Fatal //!<@~english Fatal. Used for unrecoverable errors, crashes the application (abort) right after the log record is written.
};
Logger();
Logger(const QString &defaultCategory);
~Logger();
static Logger *globalInstance();
static QString levelToString(LogLevel level);
static LogLevel levelFromString(const QString &str);
void registerAppender(AbstractAppender *appender);
void registerCategoryAppender(const QString &category, AbstractAppender *appender);
#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0)
QT_DEPRECATED_X("no longer take effect") void logToGlobalInstance(const QString &category, bool logToGlobal = false);
#endif
void setDefaultCategory(const QString &category);
QString defaultCategory() const;
void write(const QDateTime &time, LogLevel level, const char *file, int line,
const char *func, const char *category, const QString &msg);
void write(LogLevel level, const char *file, int line,
const char *func, const char *category, const QString &msg);
QDebug write(LogLevel level, const char *file, int line,
const char *func, const char *category);
void writeAssert(const char *file, int line,
const char *func, const char *condition);
private:
void write(const QDateTime &time, LogLevel level, const char *file, int line,
const char *func, const char *category,
const QString &msg, bool fromLocalInstance);
Q_DECLARE_PRIVATE(Logger)
LoggerPrivate *d_ptr;
};
DCORE_END_NAMESPACE
#endif // LOGGER_H

View File

@ -1,71 +0,0 @@
// Copyright (C) 2017 ~ 2017 Deepin Technology Co., Ltd.
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#ifndef ROLLINGFILEAPPENDER_H
#define ROLLINGFILEAPPENDER_H
#include <QDateTime>
#include <FileAppender.h>
DCORE_BEGIN_NAMESPACE
class LIBDTKCORESHARED_EXPORT RollingFileAppender : public FileAppender
{
public:
/*!
@~english
The enum DatePattern defines constants for date patterns.
\sa setDatePattern(DatePattern)
*/
enum DatePattern
{
MinutelyRollover = 0,/*!<@~english The minutely date pattern string is "'.'yyyy-MM-dd-hh-mm". */
HourlyRollover,/*!<@~english The hourly date pattern string is "yyyy-MM-dd-hh". */
HalfDailyRollover,/*!<@~english The half-daily date pattern string is "'.'yyyy-MM-dd-a". */
DailyRollover,/*!<@~english The daily date pattern string is "'.'yyyy-MM-dd". */
WeeklyRollover,/*!<@~english The weekly date pattern string is "'.'yyyy-ww". */
MonthlyRollover/*!<@~english The monthly date pattern string is "'.'yyyy-MM". */
};
RollingFileAppender(const QString &fileName = QString());
DatePattern datePattern() const;
void setDatePattern(DatePattern datePattern);
QT_DEPRECATED_X("use setDatePattern(DatePattern)") void setDatePattern(const QString &datePattern);
QT_DEPRECATED_X("use datePattern(DatePattern)") QString datePatternString() const;
void setLogFilesLimit(int limit);
int logFilesLimit() const;
void setLogSizeLimit(int limit);
qint64 logSizeLimit() const;
protected:
virtual void append(const QDateTime &time, Logger::LogLevel level, const char *file, int line,
const char *func, const QString &category, const QString &msg);
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;
qint64 m_logSizeLimit;
mutable QMutex m_rollingMutex;
};
DCORE_END_NAMESPACE
#endif // ROLLINGFILEAPPENDER_H

View File

@ -1,42 +0,0 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#ifndef DLOGGER_DEFINE_H
#define DLOGGER_DEFINE_H
#include "dtkcore_global.h"
#include <QLoggingCategory>
DCORE_BEGIN_NAMESPACE
class Logger;
class DLogHelper;
LIBDTKCORESHARED_EXPORT Logger *loggerInstance();
#define dlogger loggerInstance()
#define DLOG_CTX(category) QMessageLogContext(__FILE__, __LINE__, Q_FUNC_INFO, category)
// include DLog or dloghelper.h
#define dTrace DLogHelper(Logger::Trace, DLOG_CTX("default")).write
#define dDebug DLogHelper(Logger::Debug, DLOG_CTX("default")).write
#define dInfo DLogHelper(Logger::Info, DLOG_CTX("default")).write
#define dWarning DLogHelper(Logger::Warning, DLOG_CTX("default")).write
#define dError DLogHelper(Logger::Error, DLOG_CTX("default")).write
#define dFatal DLogHelper(Logger::Fatal, DLOG_CTX("default")).write
#define dCDebug(category) DLogHelper(Logger::Debug, DLOG_CTX(category)).write()
#define dCInfo(category) DLogHelper(Logger::Info, DLOG_CTX(category)).write()
#define dCWarning(category) DLogHelper(Logger::Warning, DLOG_CTX(category)).write()
#define dCError(category) DLogHelper(Logger::Error, DLOG_CTX(category)).write()
#define dCFatal(category) DLogHelper(Logger::Fatal, DLOG_CTX(category)).write()
#define dTraceTime DLogHelper helper(Logger::Trace, DLOG_CTX("default")); helper.timing
#define dDebugTime DLogHelper helper(Logger::Debug, DLOG_CTX("default")); helper.timing
#define dInfoTime DLogHelper helper(Logger::Info, DLOG_CTX("default")); helper.timing
#define dAssert(cond) ((!(cond)) ? loggerInstance()->writeAssert(__FILE__, __LINE__, Q_FUNC_INFO, #cond) : qt_noop())
#define dAssertX(cond, msg) ((!(cond)) ? loggerInstance()->writeAssert(__FILE__, __LINE__, Q_FUNC_INFO, msg) : qt_noop())
DCORE_END_NAMESPACE
#endif // DLOGGER_DEFINE_H

View File

@ -1,37 +0,0 @@
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#ifndef DLOGHELPER_H
#define DLOGHELPER_H
#include <dtkcore_global.h>
#include "Logger.h"
#include <QString>
#include <QDebug>
DCORE_BEGIN_NAMESPACE
class DLogHelperPrivate;
class LIBDTKCORESHARED_EXPORT DLogHelper : public QObject
{
Q_DISABLE_COPY(DLogHelper)
public:
DLogHelper(Logger::LogLevel level, const QMessageLogContext &context, QObject *parent = nullptr);
~DLogHelper();
void write(const char* msg, ...) Q_ATTRIBUTE_FORMAT_PRINTF(2, 3);
void write(const QString& msg);
QDebug write();
void timing(const QString& msg, QObject *context = nullptr);
static Logger::LogLevel levelFromQtMsgType(QtMsgType mt);
static QtMsgType qtMsgTypeFromLogLevel(Logger::LogLevel lvl);
Q_DECLARE_PRIVATE(DLogHelper)
};
DCORE_END_NAMESPACE
#endif // DLOGHELPER_H

View File

@ -1,22 +0,0 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#ifndef OUTPUTDEBUGAPPENDER_H
#define OUTPUTDEBUGAPPENDER_H
#include "dtkcore_global.h"
#include <AbstractStringAppender.h>
DCORE_BEGIN_NAMESPACE
class LIBDTKCORESHARED_EXPORT OutputDebugAppender : public AbstractStringAppender
{
protected:
virtual void append(const QDateTime &time, Logger::LogLevel level, const char *file, int line,
const char *func, const QString &category, const QString &msg);
};
DCORE_END_NAMESPACE
#endif // OUTPUTDEBUGAPPENDER_H

View File

@ -6,6 +6,7 @@ endif()
include(CMakeFindDependencyMacro)
find_dependency(Qt@QT_VERSION_MAJOR@Core)
find_dependency(Qt@QT_VERSION_MAJOR@Xml)
find_dependency(Dtk@DTK_VERSION_MAJOR@Log)
if (LINUX)
find_dependency(Qt@QT_VERSION_MAJOR@DBus)

View File

@ -8,3 +8,4 @@ Description: Deepin Tool Kit dtkcore header files
Version: @CMAKE_PROJECT_VERSION@
Libs: -L${libdir} -ldtk@DTK_VERSION_MAJOR@core
Cflags: -I${includedir} -DQT_MESSAGELOGCONTEXT
Requires: dtk@DTK_VERSION_MAJOR@log

View File

@ -8,7 +8,7 @@ QT.dtkcore.tools = @CMAKE_INSTALL_PREFIX@/@TOOL_INSTALL_DIR@
QT.dtkcore.libs = @CMAKE_INSTALL_PREFIX@/@LIBRARY_INSTALL_DIR@
QT.dtkcore.includes = @CMAKE_INSTALL_PREFIX@/@INCLUDE_INSTALL_DIR@
QT.dtkcore.frameworks =
QT.dtkcore.depends = core dbus xml
QT.dtkcore.depends = core dbus xml dtklog
QT.dtkcore.module_config = v2 ltcg
QT.dtkcore.DEFINES += QT_MESSAGELOGCONTEXT
QT_MODULES +=

View File

@ -7,6 +7,7 @@ set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core)
find_package(Dtk${DTK_VERSION_MAJOR}Log REQUIRED)
if(LINUX)
find_package(PkgConfig REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS DBus)
@ -14,9 +15,6 @@ if(LINUX)
pkg_check_modules(QGSettings REQUIRED IMPORTED_TARGET gsettings-qt) #Dtk6 removed.
endif()
if(BUILD_WITH_SYSTEMD)
pkg_check_modules(Systemd REQUIRED IMPORTED_TARGET libsystemd)
endif()
endif()
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Xml)
find_package(DtkBuildHelper REQUIRED)
@ -39,7 +37,6 @@ include(filesystem/filesystem.cmake)
#end filesystem
# start log
include(log/log.cmake)
find_package(spdlog REQUIRED)
#end log
# start settings
include(settings/settings.cmake)
@ -67,24 +64,18 @@ if(LINUX)
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::DBus
Qt${QT_VERSION_MAJOR}::Xml
Dtk${DTK_VERSION_MAJOR}::Log
)
target_link_libraries(${LIB_NAME} PRIVATE
ICU::uc
Qt${QT_VERSION_MAJOR}::CorePrivate
uchardet
spdlog::spdlog
)
if("${QT_VERSION_MAJOR}" STREQUAL "5")
target_link_libraries(${LIB_NAME} PRIVATE
PkgConfig::QGSettings
)
endif()
if(BUILD_WITH_SYSTEMD)
target_link_libraries(${LIB_NAME} PRIVATE
PkgConfig::Systemd
)
add_definitions(-DBUILD_WITH_SYSTEMD)
endif()
else()
add_library(${LIB_NAME} SHARED
@ -105,7 +96,6 @@ else()
ICU::uc
Qt${QT_VERSION_MAJOR}::CorePrivate
uchardet
spdlog::spdlog
)
if("${QT_VERSION_MAJOR}" STREQUAL "5")
target_link_libraries(${LIB_NAME} PRIVATE

View File

@ -1,167 +0,0 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "AbstractAppender.h"
DCORE_BEGIN_NAMESPACE
/*!
@~english
\class Dtk::Core::AbstractAppender
\inmodule dtkcore
\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 convenient way to
control the format of the log output.
\sa AbstractStringAppender
\sa Logger::registerAppender()
*/
/*!
@~english
\brief Constructs a AbstractAppender object.
*/
AbstractAppender::AbstractAppender()
:m_detailsLevel(Logger::Debug)
{
}
/*!
@~english
\brief Destructs the AbstractAppender object.
*/
AbstractAppender::~AbstractAppender()
{
}
/*!
@~english
\brief 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.
\return The log level.
\sa setDetailsLevel()
\sa Logger::LogLevel
*/
Logger::LogLevel AbstractAppender::detailsLevel() const
{
QMutexLocker locker(&m_detailsLevelMutex);
return m_detailsLevel;
}
/*!
@~english
\brief Sets the current details level of appender.
Default details \a level is Logger::Debug
\note This function is thread safe.
\sa detailsLevel()
\sa Logger::LogLevel
*/
void Dtk::Core::AbstractAppender::setDetailsLevel(Logger::LogLevel level)
{
QMutexLocker locker(&m_detailsLevelMutex);
m_detailsLevel = level;
}
/*!
@~english
\brief Sets the current details \a 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));
}
/*!
@~english
\brief Tries to write the log record to this logger.
This is the function called by Logger object to write a log \a message to the appender.
The \a time parameter indicates the time stamp.
The \a level parameter describes the LogLevel.
The \a file parameter is the current file name.
The \a line parameter indicates the number of lines to output.
The \a func parameter indicates the function name to output.
The \a category parameter indicates the log category.
The \a msg parameter indicates the output message.
\note This function is thread safe.
\sa Logger::write()
\sa detailsLevel()
*/
void AbstractAppender::write(const QDateTime &time, Logger::LogLevel level, const char *file, int line, const char *func, const QString &category, const QString &msg)
{
if (level < detailsLevel())
return;
QMutexLocker locker(&m_writeMutex);
append(time, level, file, line, func, category, msg);
}
/*!
@~english
\fn virtual void AbstractAppender::append(const QDateTime &timeStamp, Logger::LogLevel level, const char *file, int line,
const char *function, const QString &category, const QString &message) = 0
\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.
The \a time parameter indicates the time stamp.
The \a level parameter describes the LogLevel.
The \a file parameter is the current file name.
The \a line parameter indicates the number of lines to output.
The \a func parameter indicates the function name to output.
The \a category parameter indicates the log category.
The \a msg parameter indicates the output message.
\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()
*/
DCORE_END_NAMESPACE

View File

@ -1,481 +0,0 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "AbstractStringAppender.h"
#include <QRegularExpression>
#include <QCoreApplication>
#include <QThread>
DCORE_BEGIN_NAMESPACE
inline static QString formattedLevelWithColor(Logger::LogLevel level, QString &msg) {
switch (level) {
case Logger::Trace:
return QString("\x1b[94m%1\x1b[0m").arg(msg);
case Logger::Debug:
return QString("\x1b[36m%1\x1b[0m").arg(msg);
case Logger::Info:
return QString("\x1b[32m%1\x1b[0m").arg(msg);
case Logger::Warning:
return QString("\x1b[33m%1\x1b[0m").arg(msg);
case Logger::Error:
return QString("\x1b[31m%1\x1b[0m").arg(msg);
case Logger::Fatal:
return QString("\x1b[35m%1\x1b[0m").arg(msg);
default:
break;
}
return msg;
}
/*!
@~english
\class Dtk::Core::AbstractStringAppender
\inmodule dtkcore
\brief The AbstractStringAppender class provides a convenient base for appenders working with plain text formatted
logs.
AbstractSringAppender is the simple extension of the AbstractAppender class providing the convenient 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 = '%';
/*!
@~english
\brief Constructs a new string appender object.
*/
AbstractStringAppender::AbstractStringAppender()
: m_format(QLatin1String("%{time}{yyyy-MM-ddTHH:mm:ss.zzz} [%{type:-7}] <%{function}> %{message}\n"))
{
}
/*!
@~english
\brief 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;
}
/*!
@~english
\brief 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 standard 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 QString::arg() fieldWidth argument (and uses it
internally). For example, "%{type:-7}" will be replaced with the left padded debug level of the message
("Debug ") or something. For the more detailed description of it you may consider to look to the Qt
Reference Documentation.
Supported marker commands are:
\list
\li %{time} - timestamp. You may specify your custom timestamp \a format using the second {} brackets after the marker,
\li timestamp \a format here will be similar to those used in QDateTime::toString() function. For example,
\li "%{time}{dd-MM-yyyy, HH:mm}" may be replaced with "17-12-2010, 20:17" depending on current date and time.
\li The default \a format used here is "HH:mm:ss.zzz".
\li %{type} - Log level. Possible log levels are shown in the Logger::LogLevel enumerator.
\li %{Type} - Uppercased log level.
\li %{typeOne} - One letter log level.
\li %{TypeOne} - One uppercase letter log level.
\li %{File} - Full source file name (with path) of the file that requested log recording. Uses the __FILE__ preprocessor macro.
\li %{file} - Short file name (with stripped path).
\li %{line} - Line number in the source file. Uses the __LINE__ preprocessor macro.
\li %{Function} - Name of function that called on of the LOG_* macros. Uses the Q_FUNC_INFO macro provided with Qt.
\li %{function} - Similar to the %{Function}, but the function name is stripped using stripFunctionName
\li %{message} - The log message sent by the caller.
\li %{category} - The log category.
\li %{appname} - Application name (returned by QCoreApplication::applicationName() function).
\li %{pid} - Application pid (returned by QCoreApplication::applicationPid() function).
\li %{threadid} - ID of current thread.
\li %% - Convinient marker that is replaced with the single % mark.
\endlist
\note Format doesn't add '\\n' to the end of the \a 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;
}
/*!
@~english
\brief 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.
The \a name parameter is the function name.
\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;
QRegularExpression lambdaRegex("::<lambda\\(.*\\)>");
QRegularExpressionMatch match = lambdaRegex.match(QString::fromLatin1(info));
if (match.hasMatch()) {
hasLambda = true;
info.remove(match.capturedStart(), match.capturedLength());
}
// 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
Q_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) {
const char c = info.at(pos);
if (c == '>')
++templatecount;
else if (c == '<')
--templatecount;
--pos;
}
++pos;
info.remove(pos, end - pos + 1);
}
return info;
}
QString AbstractStringAppender::formattedString(const QDateTime &time, Logger::LogLevel level,
const char *file, int line, const char *func,
const QString &category, const QString &msg ) const {
return formattedString(time, level, file, line, func, category, msg, false);
}
/*!
@~english
\brief Returns the string to record to the logging target, formatted according to the format().
\a time The time stamp.
The \a level parameter describes the LogLevel, and the \a file parameter is the current file name,
and the \a line parameter indicates the number of lines to output.
The \a func parameter indicates the function name to output.
The \a category parameter indicates the log category.
The \a msg parameter indicates the output message.
The \a withcolor parameter indicates wether to add color to output
\sa format()
\sa setFormat(const QString&)
*/
QString AbstractStringAppender::formattedString(const QDateTime &time, Logger::LogLevel level,
const char *file, int line, const char *func,
const QString &category, const QString &msg,
bool withcolor) const
{
QString f = format();
// dtkcore无法正确解析Qt的日志格式dtk默认的日志格式并未和Qt统一解析方式需要兼容两种不同的格式。
if (f.contains(QLatin1String("time ")))
f.replace(f.indexOf(' ', f.indexOf(QLatin1String("time")) + QLatin1String("time").size()), 1, QLatin1String("}{"));
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 = time.toString(f.mid(i + 2, j));
i += j;
i += 2;
}
}
if (chunk.isNull())
chunk = time.toString(QLatin1String("HH:mm:ss.zzz"));
} else if (command == QLatin1String("type")) {
// Log level
chunk = Logger::levelToString(level);
if (withcolor) {
chunk = formattedLevelWithColor(level, chunk);
}
} else if (command == QLatin1String("Type")) {
// Uppercased log level
chunk = Logger::levelToString(level).toUpper();
if (withcolor) {
chunk = formattedLevelWithColor(level, chunk);
}
} else if (command == QLatin1String("typeOne")) {
// One letter log level
chunk = Logger::levelToString(level).left(1).toLower();
if (withcolor) {
chunk = formattedLevelWithColor(level, chunk);
}
} else if (command == QLatin1String("TypeOne")) {
// One uppercase letter log level
chunk = Logger::levelToString(level).left(1).toUpper();
if (withcolor) {
chunk = formattedLevelWithColor(level, chunk);
}
} else if (command == QLatin1String("File")) {
// Filename
chunk = QLatin1String(file);
} else if (command == QLatin1String("file")) {
// Filename without a path
chunk = QString(QLatin1String(file)).section('/', -1);
} else if (command == QLatin1String("line")) {
// Source line number
chunk = QString::number(line);
} else if (command == QLatin1String("Function")) {
// Function name, as returned by Q_FUNC_INFO
chunk = QString::fromLatin1(func);
} else if (command == QLatin1String("function")) {
// Stripped function name
chunk = stripFunctionName(func);
} else if (command == QLatin1String("message")) {
// Log message
chunk = msg;
} else if (command == QLatin1String("category")) {
// Log message
chunk = category;
} else if (command == QLatin1String("pid")) {
// Application pid
chunk = QString::number(QCoreApplication::applicationPid());
} else if (command == QLatin1String("appname")) {
// Application name
chunk = QCoreApplication::applicationName();
} else if (command == QLatin1String("threadid")) {
// Thread ID (duplicates Qt5 threadid debbuging way)
chunk = QLatin1String("0x") + QString::number(qlonglong(QThread::currentThread()->currentThread()), 16);
} else if (command == QString(formattingMarker)) {
// We simply replace the double formatting marker (%) with one
chunk = QLatin1Char(formattingMarker);
} else {
// Do not process any unknown commands
chunk = QString(formattingMarker);
chunk.append(command);
}
if (!chunk.isEmpty() && chunk != "0") {
result.append(QString(QLatin1String("%1")).arg(chunk, fieldWidth));
}
}
++i;
}
return result;
}
DCORE_END_NAMESPACE

View File

@ -1,88 +0,0 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
// Local
#include "ConsoleAppender.h"
#include <spdlog/spdlog.h>
#include <spdlog/spdlog-inl.h>
#include <spdlog/details/registry.h>
#include <spdlog/details/registry-inl.h>
#include <spdlog/sinks/stdout_color_sinks.h>
// STL
#include <iostream>
extern "C" {
#include <unistd.h>
}
DCORE_BEGIN_NAMESPACE
/*!
@~english
@class Dtk::Core::ConsoleAppender
@ingroup dlog
@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 time.
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)
{
if (!spdlog::get("console")) {
auto clogger = spdlog::stdout_color_mt("console");
clogger->set_level(spdlog::level::level_enum(detailsLevel()));
}
}
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;
}
/*!
@~english
\brief Writes the log record to the std::cerr stream.
\reimp
The \a time parameter indicates the time stamp.
The \a level parameter describes the LogLevel.
The \a file parameter is the current file name.
The \a line parameter indicates the number of lines to output.
The \a func parameter indicates the function name to output.
The \a category parameter indicates the log category.
The \a msg parameter indicates the output message.
\sa AbstractStringAppender::format()
*/
void ConsoleAppender::append(const QDateTime &time, Logger::LogLevel level, const char *file, int line,
const char *func, const QString &category, const QString &msg)
{
auto clogger = spdlog::get("console");
Q_ASSERT(clogger);
clogger->set_level(spdlog::level::level_enum(detailsLevel()));
const auto &formatted = formattedString(time, level, file, line, func, category, msg, isatty(STDOUT_FILENO));
clogger->log(spdlog::level::level_enum(level), formatted.toStdString());
}
DCORE_END_NAMESPACE

View File

@ -1,131 +0,0 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "FileAppender.h"
#include <QFileInfo>
#include "rollingfilesink_p.h"
#include <iostream>
DCORE_BEGIN_NAMESPACE
std::string loggerName(const QFile &logFile)
{
return QFileInfo(logFile).fileName().toStdString();
}
/*!
@~english
@class Dtk::Core::FileAppender
@ingroup dtkcore
@brief Simple appender that writes the log records to the plain text file.
*/
/*!
@~english
@brief Constructs the new file appender assigned to file with the given \a fileName.
*/
FileAppender::FileAppender(const QString &fileName)
{
setFileName(fileName);
}
FileAppender::~FileAppender()
{
closeFile();
}
/*!
@~english
\brief 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();
}
/*!
\brief Sets the \a s 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 (s == m_logFile.fileName())
return;
closeFile();
m_logFile.setFileName(s);
if (!spdlog::get(loggerName(s)))
rolling_logger_mt(loggerName(s),
m_logFile.fileName().toStdString(),
1024 * 1024 * 20, 0);
}
qint64 FileAppender::size() const
{
QMutexLocker locker(&m_logFileMutex);
if (auto *bs = get_sink<rolling_file_sink_mt>(loggerName(m_logFile))){
return qint64(bs->filesize());
}
return m_logFile.size();
}
bool FileAppender::openFile()
{
auto fl = spdlog::get(loggerName(m_logFile));
return fl.get();
}
/*!
@~english
\brief Write the log record to the file.
\reimp
The \a time parameter indicates the time stamp.
The \a level parameter describes the LogLevel.
The \a file parameter is the current file name.
The \a line parameter indicates the number of lines to output.
The \a func parameter indicates the func name to output.
The \a category parameter indicates the log category.
The \a msg parameter indicates the output message.
\sa fileName()
\sa AbstractStringAppender::format()
*/
void FileAppender::append(const QDateTime &time, Logger::LogLevel level, const char *file, int line,
const char *func, const QString &category, const QString &msg)
{
if (!openFile())
return;
auto fl = spdlog::get(loggerName(m_logFile));
fl->set_level(spdlog::level::level_enum(detailsLevel()));
const auto &formatted = formattedString(time, level, file, line, func, category, msg);
fl->log(spdlog::level::level_enum(level), formatted.toStdString());
fl->flush();
}
void FileAppender::closeFile()
{
spdlog::drop(loggerName(m_logFile));
}
DCORE_END_NAMESPACE

View File

@ -1,67 +0,0 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "JournalAppender.h"
#define SD_JOURNAL_SUPPRESS_LOCATION
#include <systemd/sd-journal.h>
DCORE_BEGIN_NAMESPACE
/**
* @~english
* @brief it can be used to send log to journal
* @param time journal time
* @param level log level
* @param file
* @param line Number of lines of code when writing to the log
* @param func function name
* @param category log category
* @param msg log message
*/
void JournalAppender::append(const QDateTime &time,
Logger::LogLevel level,
const char *file,
int line,
const char *func,
const QString &category,
const QString &msg)
{
JournalPriority logLevel = LOG_INFO;
switch (level) {
case Logger::Debug:
logLevel = LOG_DEBUG;
break;
case Logger::Info:
logLevel = LOG_INFO;
break;
case Logger::Warning:
logLevel = LOG_WARNING;
break;
case Logger::Error:
logLevel = LOG_ERR;
break;
case Logger::Fatal:
logLevel = LOG_CRIT;
break;
default:
logLevel = LOG_INFO;
break;
}
sd_journal_send("MESSAGE=%s",
msg.toStdString().c_str(),
"PRIORITY=%d",
logLevel,
"DTKPRIORITTY=%d",
level,
"CODE_FILE=%s",
file,
"CODE_LINE=%d",
line,
"CODE_FUNC=%s",
func,
"CODE_CATEGORY=%s",
category.toStdString().c_str(),
NULL);
}
DCORE_END_NAMESPACE

View File

@ -12,8 +12,6 @@
#include <JournalAppender.h>
#include "dstandardpaths.h"
#include "spdlog/spdlog.h"
DCORE_BEGIN_NAMESPACE
#define RULES_KEY ("rules")
@ -126,9 +124,6 @@ void DLogManagerPrivate::updateLoggingRules()
DLogManager::DLogManager()
:d_ptr(new DLogManagerPrivate(this))
{
spdlog::set_automatic_registration(true);
spdlog::set_pattern("%v");
d_ptr->initLoggingRules();
}
@ -242,7 +237,6 @@ QString DLogManager::joinPath(const QString &path, const QString &fileName){
DLogManager::~DLogManager()
{
spdlog::shutdown();
}
DCORE_END_NAMESPACE

File diff suppressed because it is too large Load Diff

View File

@ -1,59 +0,0 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
// Local
#include "win32/OutputDebugAppender.h"
#include <spdlog/sinks/msvc_sink.h>
#include <spdlog/spdlog.h>
// STL
#include <windows.h>
DCORE_BEGIN_NAMESPACE
/*!
\class Dtk::Core::OutputDebugAppender
\inmodule dtkcore
\brief Appender that writes the log records to the Microsoft Debug Log.
*/
/*!
\brief Writes the log record to the windows debug log.
\reimp
\brief Writes the log record to the windows debug log.
The \a time parameter indicates the time stamp.
The \a level parameter describes the LogLevel.
The \a file parameter is the current file name.
The \a line parameter indicates the number of lines to output.
The \a func parameter indicates the function name to output.
The \a category parameter indicates the log category.
The \a msg parameter indicates the output message.
\sa AbstractStringAppender::format()
*/
void OutputDebugAppender::append(const QDateTime &time,
Logger::LogLevel level,
const char *file,
int line,
const char *func,
const QString &category,
const QString &msg)
{
auto msvclogger = spdlog::get("msvc");
if (!msvclogger)
msvclogger = spdlog::create<spdlog::sinks::msvc_sink_mt>("msvc", true);
Q_ASSERT(msvclogger);
msvclogger->set_level(spdlog::level::level_enum(detailsLevel()));
const auto &formatted = formattedString(time, level, file, line, func, category, msg);
msvclogger->log(spdlog::level::level_enum(level), formatted.toStdString());
msvclogger->flush();
}
DCORE_END_NAMESPACE

View File

@ -1,63 +0,0 @@
# Dtk/Core/DLog
DLog is the log module of deepin tool kit for Qt/C++
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.
Logger internally uses the lazy-initialized singleton object and needs no definite initialization, but you may consider registering a log appender before calling any log recording functions or macros.
The library design of Logger allows you to simply mass-replace all occurrences of qDebug and similar calls with similar Logger macros (e.g. dDebug())
Note
Logger uses a singleton global instance which lives through all the application life cycle and self-destroys destruction of the QCoreApplication (or QApplication) instance. It needs a QCoreApplication instance to be created before any of the Logger's functions are called.
## Usage
Just add pkgconfig in .pro file
```
unix {
CONFIG+=link_pkgconfig
PKGCONFIG+=dtkcore
}
```
### Example
```cpp
#include <QCoreApplication>
#include <DLog>
using namespace Dtk::Log;
int main(int argc, char* argv[])
{
QCoreApplication app(argc, argv);
// 1 you can use standrd deepin application log format
// 1.1 log to console
DLogManager::registerConsoleAppender();
// 1.2 log to standrd deepin user cache path: ~/.cache/{organ}/{appname}/
// app.setOrganizationName("dtk-test"); // must set
// app.setApplicationName("dlog-example"); // must set
// dInfo()<< "LogFile:" << DLogManager::getlogFilePath();
// DLogManager::registerFileAppender();
// 1.3 log to stdout and file
// DLogManager::registerFileAppender();
// DLogManager::registerConsoleAppender();
// 2 Register your own dlogger format;
// ConsoleAppender* consoleAppender = new ConsoleAppender;
// consoleAppender->setFormat("[%{type:-7}] <%{Function}> %{message}\n");
// dlogger->registerAppender(consoleAppender);
dInfo("Starting the application");
int result = 1;
dWarning() << "Something went wrong." << "Result code is" << result;
return result;
}
```
\sa Dtk::Core::DLogManager

View File

@ -1,129 +0,0 @@
// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include <QDateTime>
#include <QDir>
#include <QFileInfo>
#include "RollingFileAppender.h"
#include "rollingfilesink_p.h"
DCORE_BEGIN_NAMESPACE
extern std::string loggerName(const QFile &logFile);
/*!
@~english
@class Dtk::Core::RollingFileAppender
@ingroup dlog
@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).
*/
RollingFileAppender::RollingFileAppender(const QString &fileName)
: FileAppender(fileName)
{
setLogFilesLimit(1);
setLogSizeLimit(1024 * 1024 * 20);
}
void RollingFileAppender::append(const QDateTime &time, Logger::LogLevel level, const char *file, int line,
const char *func, const QString &category, const QString &msg)
{
FileAppender::append(time, level, file, line , func, category, msg);
}
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)
{
QMutexLocker locker(&m_rollingMutex);
m_frequency = datePattern;
computeRollOverTime();
}
void RollingFileAppender::setDatePattern(const QString &/*datePattern*/)
{
}
void RollingFileAppender::setDatePatternString(const QString &/*datePatternString*/)
{
}
void RollingFileAppender::computeFrequency()
{
}
void RollingFileAppender::removeOldFiles()
{
}
void RollingFileAppender::computeRollOverTime()
{
if (auto *fs = get_sink<rolling_file_sink_mt>(loggerName(fileName()))){
return fs->set_interval(RollingInterval(m_frequency));
}
}
void RollingFileAppender::rollOver()
{
}
void RollingFileAppender::setLogFilesLimit(int limit)
{
QMutexLocker locker(&m_rollingMutex);
m_logFilesLimit = limit;
if (auto *fs = get_sink<rolling_file_sink_mt>(loggerName(fileName()))){
return fs->set_max_files(std::size_t(limit));
}
}
int RollingFileAppender::logFilesLimit() const
{
QMutexLocker locker(&m_rollingMutex);
return m_logFilesLimit;
}
void RollingFileAppender::setLogSizeLimit(int limit)
{
QMutexLocker locker(&m_rollingMutex);
m_logSizeLimit = limit;
if (auto *fs = get_sink<rolling_file_sink_mt>(loggerName(fileName()))){
return fs->set_max_size(std::size_t(limit));
}
}
qint64 RollingFileAppender::logSizeLimit() const
{
QMutexLocker locker(&m_rollingMutex);
return m_logSizeLimit;
}
DCORE_END_NAMESPACE

View File

@ -1,158 +0,0 @@
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "dloghelper.h"
#include "Logger.h"
#include <QCoreApplication>
#include <QElapsedTimer>
#include <private/qobject_p.h>
#include <iostream>
DCORE_BEGIN_NAMESPACE
class DLogHelperPrivate : public QObjectPrivate {
public:
// Functions.
explicit DLogHelperPrivate(int version = QObjectPrivateVersion)
: QObjectPrivate(version) {
}
~DLogHelperPrivate() {
}
void setContext(const QMessageLogContext &ctx) {
file = ctx.file;
line = ctx.line;
function = ctx.function;
category = ctx.category;
}
void setLevel(Logger::LogLevel lvl) {
level = lvl;
}
const char *file = nullptr;
const char *function = nullptr;
const char *category = nullptr;
int line = 0;
Logger::LogLevel level = Logger::LogLevel::Debug;
};
DLogHelper::DLogHelper(Logger::LogLevel level, const QMessageLogContext &context, QObject *parent)
: QObject(*new DLogHelperPrivate, parent)
{
d_func()->setContext(context);
d_func()->setLevel(level);
}
DLogHelper::~DLogHelper()
{
}
void DLogHelper::write(const char* msg, ...)
{
QString message;
va_list va;
va_start(va, msg);
message = QString::vasprintf(msg, va);
va_end(va);
write(message);
}
void DLogHelper::write(const QString &msg)
{
Q_D(DLogHelper);
Logger::globalInstance()->write(d->level, d->file, d->line,
d->function, d->category, msg);
}
QDebug DLogHelper::write()
{
Q_D(DLogHelper);
return Logger::globalInstance()->write(d->level, d->file, d->line,
d->function, d->category);
}
void DLogHelper::timing(const QString &msg, QObject *context/* = nullptr*/)
{
if (!context)
context = this;
QElapsedTimer *elapsedTimer = new QElapsedTimer;
elapsedTimer->start();
QObject::connect(context, &QObject::destroyed, [elapsedTimer, msg, this](){
QString message;
message = msg + (QLatin1String(" finished in "));
qint64 elapsed = elapsedTimer->elapsed();
delete elapsedTimer;
if (elapsed >= 10000)
message += QString::number(elapsed / 1000) + QLatin1String("s.");
else
message += QString::number(elapsed) + QLatin1String("ms.");
write(message);
});
}
Logger::LogLevel DLogHelper::levelFromQtMsgType(QtMsgType mt)
{
Logger::LogLevel level;
switch (mt)
{
case QtDebugMsg:
level = Logger::Debug;
break;
#if QT_VERSION >= 0x050500
case QtInfoMsg:
level = Logger::Info;
break;
#endif
case QtWarningMsg:
level = Logger::Warning;
break;
case QtCriticalMsg:
level = Logger::Error;
break;
case QtFatalMsg:
level = Logger::Fatal;
break;
}
return level;
}
QtMsgType DLogHelper::qtMsgTypeFromLogLevel(Logger::LogLevel lvl)
{
QtMsgType mt;
switch (lvl)
{
case Logger::Debug:
mt = QtDebugMsg;
break;
#if QT_VERSION >= 0x050500
case Logger::Info:
mt = QtInfoMsg;
break;
#endif
case Logger::Warning:
mt = QtWarningMsg;
break;
case Logger::Error:
mt = QtCriticalMsg;
break;
case Logger::Fatal:
mt = QtFatalMsg;
break;
default:
mt = QtWarningMsg;
}
return mt;
}
DCORE_END_NAMESPACE

View File

@ -1,34 +1,12 @@
file(GLOB LOG_HEADER
${CMAKE_CURRENT_LIST_DIR}/../../include/log/*.h
${CMAKE_CURRENT_LIST_DIR}/../../include/log/LogManager.h
)
set(LOG_SOURCE
${CMAKE_CURRENT_LIST_DIR}/RollingFileAppender.cpp
${CMAKE_CURRENT_LIST_DIR}/Logger.cpp
${CMAKE_CURRENT_LIST_DIR}/FileAppender.cpp
${CMAKE_CURRENT_LIST_DIR}/ConsoleAppender.cpp
${CMAKE_CURRENT_LIST_DIR}/AbstractStringAppender.cpp
${CMAKE_CURRENT_LIST_DIR}/AbstractAppender.cpp
${CMAKE_CURRENT_LIST_DIR}/LogManager.cpp
${CMAKE_CURRENT_LIST_DIR}/dloghelper.cpp
${CMAKE_CURRENT_LIST_DIR}/rollingfilesink_p.h
)
if(BUILD_WITH_SYSTEMD AND UNIX AND NOT APPLE)
list(APPEND LOG_SOURCE
${CMAKE_CURRENT_LIST_DIR}/JournalAppender.cpp
)
endif()
set(log_SRCS
${LOG_HEADER}
${LOG_SOURCE}
)
if(WIN32)
set(log_SRCS
${LOG_HEADER}
${LOG_SOURCE}
${CMAKE_CURRENT_LIST_DIR}/OutputDebugAppender.cpp
${CMAKE_CURRENT_LIST_DIR}/../../include/log/win32/OutputDebugAppender.h
)
else()
set(log_SRCS
${LOG_HEADER}
${LOG_SOURCE}
)
endif()

View File

@ -1,311 +0,0 @@
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#pragma once
#include <spdlog/spdlog.h>
#include <spdlog/details/file_helper.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/fmt/fmt.h>
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/os.h>
#include <QDir>
#include <chrono>
#include <cstdio>
#include <ctime>
#include <mutex>
#include <string>
#include <dtkcore_global.h>
#ifndef SPDLOG_VERSION_CHECK
#define SPDLOG_VERSION_CHECK(major, minor, patch) (major * 10000 + minor * 100 + patch)
#endif
DCORE_BEGIN_NAMESPACE
using namespace spdlog;
/*
* Generator of Hourly log file names in format basename.ext.YYYY-MM-DD-HH-MM-SS
*/
struct rolling_filename_calculator
{
// Create filename for the form basename.ext.YYYY-MM-DD-HH-MM-SS
static filename_t calc_filename(const filename_t &filename, const tm &now_tm)
{
#if SPDLOG_VERSION < SPDLOG_VERSION_CHECK(1,10,0)
#if SPDLOG_VERSION < SPDLOG_VERSION_CHECK(1,4,0)
std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::basic_memory_buffer<char, 250>, fmt::basic_string_view<wchar_t>>::type w;
#else
std::conditional<std::is_same<filename_t::value_type, char>::value, spdlog::memory_buf_t, spdlog::wmemory_buf_t>::type w;
#endif
fmt::format_to(w, SPDLOG_FILENAME_T("{}.{:04d}-{:02d}-{:02d}-{:02d}-{:02d}-{:02d}"), filename,
now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday,
now_tm.tm_hour, now_tm.tm_min, now_tm.tm_sec);
return fmt::to_string(w);
#else
return fmt_lib::format(SPDLOG_FILENAME_T("{}.{:04d}-{:02d}-{:02d}-{:02d}-{:02d}-{:02d}"), filename,
now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday,
now_tm.tm_hour, now_tm.tm_min, now_tm.tm_sec);
#endif
}
};
enum RollingInterval
{
RI_Minutely = 0,
RI_Hourly,
RI_HalfDaily,
RI_Daily,
RI_Weekly,
RI_Monthly
};
/*
* Rolling file sink based on time and file size.
* If max_files > 0, retain only the last max_files and delete previous.
*/
template<typename Mutex, typename FileNameCalc = rolling_filename_calculator>
class rolling_file_sink final : public sinks::base_sink<Mutex>
{
public:
// create rolling file sink which rollings on given interval
rolling_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files,
bool rolling_on_open = false, RollingInterval interval = RI_Daily)
: base_filename_(std::move(base_filename))
, rolling_on_open_(rolling_on_open)
, interval_(interval)
, filenames_q_()
{
set_max_size(max_size);
set_max_files(max_files);
auto filename = base_filename_;
file_helper_.open(filename, false);
current_size_ = file_helper_.size(); // expensive. called only once
rotation_tp_ = next_rotation_tp_();
if (rolling_on_open && current_size_ > 0)
{
rolling_();
current_size_ = 0;
}
}
filename_t filename()
{
std::lock_guard<Mutex> lock(sinks::base_sink<Mutex>::mutex_);
return file_helper_.filename();
}
size_t filesize()
{
std::lock_guard<Mutex> lock(sinks::base_sink<Mutex>::mutex_);
return file_helper_.size();
}
void set_max_files(std::size_t max_files)
{
std::lock_guard<Mutex> lock(sinks::base_sink<Mutex>::mutex_);
if (max_files > 200000)
{
throw spdlog_ex("rolling sink constructor: max_files arg cannot exceed 200000");
}
max_files_ = max_files;
if (max_files > 0)
init_filenames_q_();
}
void set_max_size(std::size_t max_size)
{
std::lock_guard<Mutex> lock(sinks::base_sink<Mutex>::mutex_);
if (max_size == 0)
{
throw spdlog_ex("rolling sink constructor: max_size arg cannot be zero");
}
max_size_ = max_size;
}
void set_interval(RollingInterval interval)
{
std::lock_guard<Mutex> lock(sinks::base_sink<Mutex>::mutex_);
interval_ = interval;
rotation_tp_ = next_rotation_tp_();
}
protected:
void sink_it_(const details::log_msg &msg) override
{
#if SPDLOG_VERSION < SPDLOG_VERSION_CHECK(1,4,0)
fmt::memory_buffer formatted;
#else
memory_buf_t formatted;
#endif
sinks::base_sink<Mutex>::formatter_->format(msg, formatted);
auto new_size = current_size_ + formatted.size();
auto time = msg.time;
bool should_rolling = time >= rotation_tp_ || new_size > max_size_;
if (should_rolling)
{
file_helper_.flush();
if (file_helper_.size() > 0)
{
rolling_();
new_size = formatted.size();
}
}
file_helper_.write(formatted);
current_size_ = new_size;
// Do the cleaning only at the end because it might throw on failure.
if (should_rolling && max_files_ > 0)
{
delete_old_();
}
}
void flush_() override
{
file_helper_.flush();
}
private:
void init_filenames_q_()
{
filenames_q_.clear();
QDir dir(QString::fromStdString(base_filename_));
dir.cdUp();
auto namefilter = QFileInfo(base_filename_.c_str()).fileName().append("*");
auto fileInfos = dir.entryInfoList({ namefilter }, QDir::NoDotAndDotDot | QDir::Files, QDir::Name);
for (const auto &fi : fileInfos) {
if (fi.filePath().compare(base_filename_.c_str()))
filenames_q_.push_back(std::move(fi.filePath().toStdString()));
}
}
tm now_tm(log_clock::time_point tp)
{
time_t tnow = log_clock::to_time_t(tp);
return spdlog::details::os::localtime(tnow);
}
log_clock::time_point next_rotation_tp_()
{
auto now = log_clock::now();
tm date = now_tm(now);
auto rotation_time = log_clock::from_time_t(std::mktime(&date));
switch (interval_) {
case RI_Minutely:
date.tm_min += 1;
break;
case RI_Hourly:
date.tm_hour += 1;
break;
case RI_HalfDaily:
date.tm_hour += 12;
break;
case RI_Daily:
date.tm_mday += 1;
break;
case RI_Weekly:
date.tm_mday += 7;
break;
case RI_Monthly:
date.tm_mon += 1;
break;
}
rotation_time = log_clock::from_time_t(std::mktime(&date));
return rotation_time;
}
// Delete the file N rotations ago.
// Throw spdlog_ex on failure to delete the old file.
void delete_old_()
{
using details::os::filename_to_str;
using details::os::remove;
// base_filename_ not in filenames_q_
while (filenames_q_.size() > max_files_ - 1)
{
auto old_filename = std::move(filenames_q_.front());
filenames_q_.pop_front();
bool ok = remove(old_filename) == 0;
if (!ok)
{
filenames_q_.push_back(std::move(old_filename));
throw(spdlog_ex("Failed removing file " + filename_to_str(old_filename), errno));
}
}
}
void rolling_()
{
using details::os::filename_to_str;
file_helper_.close();
// xxx.log == > xxx.log.YYYY-MM-DD-HH-MM-SS
auto backupName = FileNameCalc::calc_filename(base_filename_, now_tm(log_clock::now()));
if (details::os::rename(base_filename_, backupName))
{
file_helper_.reopen(true); // truncate the log file anyway to prevent it to grow beyond its limit!
current_size_ = 0;
throw spdlog_ex("rolling_file_sink: failed renaming " + filename_to_str(base_filename_) + " to " + filename_to_str(backupName), errno);
}
filenames_q_.push_back(std::move(backupName));
rotation_tp_ = next_rotation_tp_();
file_helper_.reopen(true);
}
filename_t base_filename_;
log_clock::time_point rotation_tp_;
details::file_helper file_helper_;
bool rolling_on_open_;
std::size_t max_size_;
std::size_t max_files_;
std::size_t current_size_;
RollingInterval interval_;
std::list<filename_t> filenames_q_;
};
using rolling_file_sink_mt = rolling_file_sink<std::mutex>;
using rolling_file_sink_st = rolling_file_sink<details::null_mutex>;
//
// factory functions
//
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> rolling_logger_mt(const std::string &logger_name, const filename_t &filename, std::size_t max_file_size,
std::size_t max_files, bool rolling_on_open = false, RollingInterval interval = RI_Daily)
{
return Factory::template create<rolling_file_sink_mt>(logger_name, filename, max_file_size, max_files, rolling_on_open, interval);
}
template<typename Factory = spdlog::synchronous_factory>
inline std::shared_ptr<logger> rolling_logger_st(const std::string &logger_name, const filename_t &filename, std::size_t max_file_size,
std::size_t max_files, bool rolling_on_open = false, RollingInterval interval = RI_Daily)
{
return Factory::template create<rolling_file_sink_st>(logger_name, filename, max_file_size, max_files, rolling_on_open, interval);
}
template<typename Sink>
Sink *get_sink(const std::string &logger_name)
{
Sink *sink = nullptr;
auto fl = spdlog::get(logger_name);
if (!fl)
return sink;
spdlog::sink_ptr s_ptr = fl->sinks()[0];
sink = dynamic_cast<Sink *>(s_ptr.get());
return sink;
}
DCORE_END_NAMESPACE

View File

@ -1,157 +0,0 @@
// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include <gtest/gtest.h>
#include <QFile>
#include <QLocale>
#include <QTemporaryFile>
#include "log/Logger.h"
#include "log/dloghelper.h"
#include "log/FileAppender.h"
#include "log/ConsoleAppender.h"
#include "log/RollingFileAppender.h"
DCORE_USE_NAMESPACE
class ut_Logger: public testing::Test
{
protected:
void SetUp() override;
void TearDown() override;
QString tmpFileName() {
Q_ASSERT(m_tmpFile);
return m_tmpFile->fileName();
}
Logger *m_logger = nullptr;
QTemporaryFile *m_tmpFile = nullptr;
};
void ut_Logger::SetUp()
{
m_logger = new Logger;
m_tmpFile = new QTemporaryFile;
m_tmpFile->open();
}
void ut_Logger::TearDown()
{
if (m_logger) {
delete m_logger;
m_logger = nullptr;
}
m_tmpFile->close();
delete m_tmpFile;
}
TEST_F(ut_Logger, testLevelToString)
{
QString trace = Logger::levelToString(Logger::Trace);
ASSERT_EQ(trace, "Trace");
QString debug = Logger::levelToString(Logger::Debug);
ASSERT_EQ(debug, "Debug");
QString info = Logger::levelToString(Logger::Info);
ASSERT_EQ(info, "Info");
QString warning = Logger::levelToString(Logger::Warning);
ASSERT_EQ(warning, "Warning");
QString error = Logger::levelToString(Logger::Error);
ASSERT_EQ(error, "Error");
QString fatal = Logger::levelToString(Logger::Fatal);
ASSERT_EQ(fatal, "Fatal");
}
TEST_F(ut_Logger, testLevelFromString)
{
Logger::LogLevel trace = Logger::levelFromString("Trace");
ASSERT_EQ(trace, Logger::Trace);
Logger::LogLevel debug = Logger::levelFromString("Debug");
ASSERT_EQ(debug, Logger::Debug);
Logger::LogLevel info = Logger::levelFromString("Info");
ASSERT_EQ(info, Logger::Info);
Logger::LogLevel warning = Logger::levelFromString("Warning");
ASSERT_EQ(warning, Logger::Warning);
Logger::LogLevel error = Logger::levelFromString("Error");
ASSERT_EQ(error, Logger::Error);
Logger::LogLevel fatal = Logger::levelFromString("Fatal");
ASSERT_EQ(fatal, Logger::Fatal);
}
TEST_F(ut_Logger, testGlobalInstance)
{
ASSERT_TRUE(Logger::globalInstance());
}
TEST_F(ut_Logger, testRegisterAppender)
{
Logger* gLogger = Logger::globalInstance();
FileAppender *fileAppener = new FileAppender(tmpFileName());
if (fileAppener->detailsLevel() > Logger::Trace)
fileAppener->setDetailsLevel(Logger::Trace);
gLogger->registerAppender(fileAppener);
ASSERT_TRUE(fileAppener->size() == 0);
dInfo("testRegisterAppender");
ASSERT_TRUE(fileAppener->size() != 0);
ConsoleAppender *consoleAppener = new ConsoleAppender();
if (consoleAppener->detailsLevel() > Logger::Trace)
consoleAppener->setDetailsLevel(Logger::Trace);
gLogger->registerAppender(consoleAppener);
consoleAppener->ignoreEnvironmentPattern(false);
QString format = consoleAppener->format();
consoleAppener->setFormat("[%{file}: %{line} %{type:-7}] <%{function}> %{message}\n");
dTrace("testRegisterAppender");
RollingFileAppender *rollingFileAppender = new RollingFileAppender("/tmp/rollLog");
if (rollingFileAppender->detailsLevel() > Logger::Trace)
rollingFileAppender->setDetailsLevel(Logger::Trace);
gLogger->registerAppender(rollingFileAppender);
rollingFileAppender->setLogFilesLimit(2);
ASSERT_TRUE(rollingFileAppender->logFilesLimit() == 2);
rollingFileAppender->setDatePattern(RollingFileAppender::MinutelyRollover);
ASSERT_TRUE(rollingFileAppender->datePattern() == RollingFileAppender::MinutelyRollover);
dTrace("testRegisterAppender");
rollingFileAppender->setDatePattern(RollingFileAppender::HourlyRollover);
ASSERT_TRUE(rollingFileAppender->datePattern() == RollingFileAppender::HourlyRollover);
dTrace("testRegisterAppender");
rollingFileAppender->setDatePattern(RollingFileAppender::HalfDailyRollover);
ASSERT_TRUE(rollingFileAppender->datePattern() == RollingFileAppender::HalfDailyRollover);
dTrace("testRegisterAppender");
}
TEST_F(ut_Logger, testRegisterCategoryAppender)
{
qInfo() << "tmpFileName()" << tmpFileName();
Logger* gLogger = Logger::globalInstance();
FileAppender *fileAppener = new FileAppender(tmpFileName());
gLogger->registerCategoryAppender("testRegisterCategoryAppender", fileAppener);
if (fileAppener->detailsLevel() > Logger::Trace)
fileAppener->setDetailsLevel(Logger::Trace);
ASSERT_TRUE(fileAppener->size() == 0);
dCDebug("testRegisterCategoryAppender") << "testRegisterCategoryAppender";
ASSERT_TRUE(fileAppener->size() != 0);
}
TEST_F(ut_Logger, testLogToGlobalInstance)
{
Logger* gLogger = Logger::globalInstance();
FileAppender *fileAppener = new FileAppender(tmpFileName());
if (fileAppener->detailsLevel() > Logger::Trace)
fileAppener->setDetailsLevel(Logger::Trace);
gLogger->registerAppender(fileAppener);
ASSERT_TRUE(fileAppener->size() == 0);
dTrace("testRegisterAppender");
ASSERT_TRUE(fileAppener->size() != 0);
}
TEST_F(ut_Logger, testSetDefaultCategory)
{
m_logger->setDefaultCategory("testSetDefaultCategory");
ASSERT_EQ(m_logger->defaultCategory(), "testSetDefaultCategory");
}
TEST_F(ut_Logger, testDefaultCategory)
{
ASSERT_EQ(m_logger->defaultCategory(), "");
}