mirror of https://github.com/linuxdeepin/dtkcore
feat: use spdlog reimplement dlog
reimplement dlog use `DLogHelper` instead of `CuteMessageLogger` `LoggerTimingHelper` keep CuteMessage symbol for compatibility (fix undefined symbol: _ZNK3Dtk4Core17CuteMessageLogger5writeEPKcz)
This commit is contained in:
parent
a4eba32e2b
commit
24a29a0f9f
|
@ -9,7 +9,7 @@ pkgdesc='DTK core modules'
|
|||
arch=('x86_64' 'aarch64')
|
||||
url="https://github.com/linuxdeepin/dtkcore"
|
||||
license=('LGPL3')
|
||||
depends=('deepin-desktop-base-git' 'gsettings-qt' 'dtkcommon-git' 'lshw' 'uchardet' 'icu' 'libsystemd')
|
||||
depends=('deepin-desktop-base-git' 'gsettings-qt' 'dtkcommon-git' 'lshw' 'uchardet' 'icu' 'libsystemd' 'spdlog')
|
||||
makedepends=('git' 'qt5-tools' 'ninja' 'cmake' 'doxygen')
|
||||
conflicts=('dtkcore')
|
||||
provides=('dtkcore')
|
||||
|
|
|
@ -5,7 +5,7 @@ Maintainer: Deepin Packages Builder <packages@deepin.com>
|
|||
Build-Depends: debhelper-compat ( =12), pkg-config,
|
||||
qttools5-dev-tools, qtbase5-private-dev, doxygen,
|
||||
libgsettings-qt-dev, libgtest-dev, libdtkcommon-dev, cmake,
|
||||
libuchardet-dev, libicu-dev, libsystemd-dev
|
||||
libuchardet-dev, libicu-dev, libsystemd-dev, libspdlog-dev
|
||||
Standards-Version: 3.9.8
|
||||
|
||||
Package: libdtkcore5
|
||||
|
|
|
@ -6,3 +6,4 @@
|
|||
#include "AbstractStringAppender.h"
|
||||
#include "AbstractAppender.h"
|
||||
#include "JournalAppender.h"
|
||||
#include "dloghelper.h"
|
||||
|
|
|
@ -12,12 +12,10 @@
|
|||
|
||||
DCORE_BEGIN_NAMESPACE
|
||||
|
||||
class ConsoleAppender;
|
||||
class RollingFileAppender;
|
||||
class JournalAppender;
|
||||
|
||||
class DLogManagerPrivate;
|
||||
class LIBDTKCORESHARED_EXPORT DLogManager
|
||||
{
|
||||
Q_DISABLE_COPY(DLogManager)
|
||||
public:
|
||||
static void registerConsoleAppender();
|
||||
static void registerFileAppender();
|
||||
|
@ -34,13 +32,6 @@ public:
|
|||
static void setLogFormat(const QString &format);
|
||||
|
||||
private:
|
||||
//TODO: move it to private class (DTK6)
|
||||
QString m_format;
|
||||
QString m_logPath;
|
||||
ConsoleAppender* m_consoleAppender;
|
||||
RollingFileAppender* m_rollingFileAppender;
|
||||
JournalAppender* m_journalAppender;
|
||||
|
||||
void initConsoleAppender();
|
||||
void initRollingFileAppender();
|
||||
void initJournalAppender();
|
||||
|
@ -52,8 +43,9 @@ private:
|
|||
}
|
||||
explicit DLogManager();
|
||||
~DLogManager();
|
||||
DLogManager(const DLogManager &);
|
||||
DLogManager & operator = (const DLogManager &);
|
||||
|
||||
QScopedPointer<DLogManagerPrivate> d_ptr;
|
||||
Q_DECLARE_PRIVATE(DLogManager)
|
||||
};
|
||||
|
||||
DCORE_END_NAMESPACE
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <QString>
|
||||
#include <QDebug>
|
||||
#include <QDateTime>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include "dloggerdefs.h"
|
||||
|
||||
|
@ -63,88 +62,5 @@ private:
|
|||
LoggerPrivate *d_ptr;
|
||||
};
|
||||
|
||||
|
||||
class LIBDTKCORESHARED_EXPORT CuteMessageLogger
|
||||
{
|
||||
Q_DISABLE_COPY(CuteMessageLogger)
|
||||
|
||||
public:
|
||||
Q_DECL_CONSTEXPR CuteMessageLogger(Logger *l, Logger::LogLevel level,
|
||||
const char *file, int line, const char *func)
|
||||
: m_l(l),
|
||||
m_level(level),
|
||||
m_file(file),
|
||||
m_line(line),
|
||||
m_function(func),
|
||||
m_category(nullptr)
|
||||
{}
|
||||
|
||||
Q_DECL_CONSTEXPR CuteMessageLogger(Logger *l, Logger::LogLevel level, const char *file,
|
||||
int line, const char *func, const char *category)
|
||||
: m_l(l),
|
||||
m_level(level),
|
||||
m_file(file),
|
||||
m_line(line),
|
||||
m_function(func),
|
||||
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 LIBDTKCORESHARED_EXPORT LoggerTimingHelper
|
||||
{
|
||||
Q_DISABLE_COPY(LoggerTimingHelper)
|
||||
public:
|
||||
inline explicit LoggerTimingHelper(Logger *l, Logger::LogLevel level,
|
||||
const char *file, int line, const char *func)
|
||||
: m_logger(l),
|
||||
m_logLevel(level),
|
||||
m_file(file),
|
||||
m_line(line),
|
||||
m_function(func)
|
||||
{}
|
||||
|
||||
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;
|
||||
QElapsedTimer m_time;
|
||||
Logger::LogLevel m_logLevel;
|
||||
const char *m_file;
|
||||
int m_line;
|
||||
const char *m_function;
|
||||
QString m_block;
|
||||
};
|
||||
|
||||
DCORE_END_NAMESPACE
|
||||
#endif // LOGGER_H
|
||||
|
|
|
@ -35,9 +35,9 @@ class LIBDTKCORESHARED_EXPORT RollingFileAppender : public FileAppender
|
|||
|
||||
DatePattern datePattern() const;
|
||||
void setDatePattern(DatePattern datePattern);
|
||||
void setDatePattern(const QString &datePattern);
|
||||
QT_DEPRECATED_X("use setDatePattern(DatePattern)") void setDatePattern(const QString &datePattern);
|
||||
|
||||
QString datePatternString() const;
|
||||
QT_DEPRECATED_X("use datePattern(DatePattern)") QString datePatternString() const;
|
||||
|
||||
void setLogFilesLimit(int limit);
|
||||
int logFilesLimit() const;
|
||||
|
|
|
@ -5,52 +5,38 @@
|
|||
#define DLOGGER_DEFINE_H
|
||||
|
||||
#include "dtkcore_global.h"
|
||||
#include <QLoggingCategory>
|
||||
|
||||
DCORE_BEGIN_NAMESPACE
|
||||
|
||||
class Logger;
|
||||
class CuteMessageLogger;
|
||||
class LoggerTimingHelper;
|
||||
class DLogHelper;
|
||||
LIBDTKCORESHARED_EXPORT Logger *loggerInstance();
|
||||
#define logger loggerInstance()
|
||||
#define dlogger loggerInstance()
|
||||
|
||||
#define dTrace CuteMessageLogger(loggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO).write
|
||||
#define dDebug CuteMessageLogger(loggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO).write
|
||||
#define dInfo CuteMessageLogger(loggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO).write
|
||||
#define dWarning CuteMessageLogger(loggerInstance(), Logger::Warning, __FILE__, __LINE__, Q_FUNC_INFO).write
|
||||
#define dError CuteMessageLogger(loggerInstance(), Logger::Error, __FILE__, __LINE__, Q_FUNC_INFO).write
|
||||
#define dFatal CuteMessageLogger(loggerInstance(), Logger::Fatal, __FILE__, __LINE__, Q_FUNC_INFO).write
|
||||
#define DLOG_CTX(category) QMessageLogContext(__FILE__, __LINE__, Q_FUNC_INFO, category)
|
||||
|
||||
#define dCDebug(category) CuteMessageLogger(loggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO, category).write()
|
||||
#define dCInfo(category) CuteMessageLogger(loggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO, category).write()
|
||||
#define dCWarning(category) CuteMessageLogger(loggerInstance(), Logger::Warning, __FILE__, __LINE__, Q_FUNC_INFO, category).write()
|
||||
#define dCError(category) CuteMessageLogger(loggerInstance(), Logger::Error, __FILE__, __LINE__, Q_FUNC_INFO, category).write()
|
||||
#define dCFatal(category) CuteMessageLogger(loggerInstance(), Logger::Fatal, __FILE__, __LINE__, Q_FUNC_INFO, category).write()
|
||||
// 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 dTraceTime LoggerTimingHelper loggerTimingHelper(loggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start
|
||||
#define dDebugTime LoggerTimingHelper loggerTimingHelper(loggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start
|
||||
#define dInfoTime LoggerTimingHelper loggerTimingHelper(loggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start
|
||||
#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())
|
||||
|
||||
#define dCategory(category) \
|
||||
private:\
|
||||
Logger* loggerInstance()\
|
||||
{\
|
||||
static Logger customLoggerInstance(category);\
|
||||
return &customLoggerInstance;\
|
||||
}\
|
||||
|
||||
#define dGlobalCategory(category) \
|
||||
private:\
|
||||
Logger* loggerInstance()\
|
||||
{\
|
||||
static Logger customLoggerInstance(category);\
|
||||
customLoggerInstance.logToGlobalInstance(category, true);\
|
||||
return &customLoggerInstance;\
|
||||
}\
|
||||
|
||||
DCORE_END_NAMESPACE
|
||||
|
||||
#endif // DLOGGER_DEFINE_H
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
// 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
|
|
@ -41,6 +41,7 @@ include(filesystem/filesystem.cmake)
|
|||
#end filesystem
|
||||
# start log
|
||||
include(log/log.cmake)
|
||||
find_package(spdlog REQUIRED)
|
||||
#end log
|
||||
# start settings
|
||||
include(settings/settings.cmake)
|
||||
|
@ -73,6 +74,7 @@ if(LINUX)
|
|||
ICU::uc
|
||||
Qt${QT_VERSION_MAJOR}::CorePrivate
|
||||
uchardet
|
||||
spdlog::spdlog
|
||||
)
|
||||
if("${QT_VERSION_MAJOR}" STREQUAL "5")
|
||||
target_link_libraries(${LIB_NAME} PRIVATE
|
||||
|
@ -105,6 +107,7 @@ else()
|
|||
ICU::uc
|
||||
Qt${QT_VERSION_MAJOR}::CorePrivate
|
||||
uchardet
|
||||
spdlog::spdlog
|
||||
)
|
||||
if("${QT_VERSION_MAJOR}" STREQUAL "5")
|
||||
target_link_libraries(${LIB_NAME} PRIVATE
|
||||
|
@ -117,6 +120,7 @@ set_target_properties(${LIB_NAME} PROPERTIES
|
|||
SOVERSION ${CMAKE_PROJECT_VERSION_MAJOR}
|
||||
EXPORT_NAME Core
|
||||
)
|
||||
|
||||
target_include_directories(${LIB_NAME} PRIVATE
|
||||
${uchardet_INCLUDE_DIRS}
|
||||
)
|
||||
|
|
|
@ -3,8 +3,12 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
// Local
|
||||
|
||||
#include "ConsoleAppender.h"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
|
||||
// STL
|
||||
#include <iostream>
|
||||
extern "C" {
|
||||
|
@ -33,20 +37,23 @@ ConsoleAppender::ConsoleAppender()
|
|||
: AbstractStringAppender()
|
||||
,m_ignoreEnvPattern(false)
|
||||
{
|
||||
setFormat("[%{type:-7}] <%{function}> %{message}\n");
|
||||
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");
|
||||
return (m_ignoreEnvPattern || envPattern.isEmpty()) ? AbstractStringAppender::format() : (envPattern + "\n");
|
||||
}
|
||||
|
||||
|
||||
void ConsoleAppender::ignoreEnvironmentPattern(bool ignore)
|
||||
{
|
||||
m_ignoreEnvPattern = ignore;
|
||||
m_ignoreEnvPattern = ignore;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -67,8 +74,12 @@ void ConsoleAppender::ignoreEnvironmentPattern(bool ignore)
|
|||
void ConsoleAppender::append(const QDateTime &time, Logger::LogLevel level, const char *file, int line,
|
||||
const char *func, const QString &category, const QString &msg)
|
||||
{
|
||||
bool isAtty = isatty(STDERR_FILENO);
|
||||
std::cerr << qPrintable(formattedString(time, level, file, line, func, category, msg, isAtty));
|
||||
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, true);
|
||||
clogger->log(spdlog::level::level_enum(level), formatted.toStdString());
|
||||
}
|
||||
|
||||
DCORE_END_NAMESPACE
|
||||
|
|
|
@ -4,10 +4,18 @@
|
|||
|
||||
#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
|
||||
|
@ -52,29 +60,36 @@ QString FileAppender::fileName() const
|
|||
void FileAppender::setFileName(const QString &s)
|
||||
{
|
||||
QMutexLocker locker(&m_logFileMutex);
|
||||
if (m_logFile.isOpen())
|
||||
m_logFile.close();
|
||||
|
||||
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()
|
||||
{
|
||||
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;
|
||||
auto fl = spdlog::get(loggerName(m_logFile));
|
||||
|
||||
return fl.get();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -96,21 +111,19 @@ bool FileAppender::openFile()
|
|||
void FileAppender::append(const QDateTime &time, Logger::LogLevel level, const char *file, int line,
|
||||
const char *func, const QString &category, const QString &msg)
|
||||
{
|
||||
QMutexLocker locker(&m_logFileMutex);
|
||||
|
||||
if (openFile())
|
||||
{
|
||||
m_logStream << formattedString(time, level, file, line, func, category, msg);
|
||||
m_logStream.flush();
|
||||
m_logFile.flush();
|
||||
}
|
||||
if (!openFile())
|
||||
return;
|
||||
|
||||
auto fl = spdlog::get(loggerName(m_logFile));
|
||||
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()
|
||||
{
|
||||
QMutexLocker locker(&m_logFileMutex);
|
||||
m_logFile.close();
|
||||
spdlog::drop(loggerName(m_logFile));
|
||||
}
|
||||
|
||||
DCORE_END_NAMESPACE
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <JournalAppender.h>
|
||||
#include "dstandardpaths.h"
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
DCORE_BEGIN_NAMESPACE
|
||||
|
||||
// Courtesy qstandardpaths_unix.cpp
|
||||
|
@ -26,6 +28,26 @@ static void appendOrganizationAndApp(QString &path)
|
|||
#endif
|
||||
}
|
||||
|
||||
#define DEFAULT_FMT "%{time}{yyyy-MM-dd, HH:mm:ss.zzz} [%{type:-7}] [%{file:-20} %{function:-35} %{line}] %{message}"
|
||||
|
||||
class DLogManagerPrivate {
|
||||
public:
|
||||
explicit DLogManagerPrivate(DLogManager *q)
|
||||
: m_format(DEFAULT_FMT)
|
||||
, q_ptr(q)
|
||||
{
|
||||
}
|
||||
|
||||
QString m_format;
|
||||
QString m_logPath;
|
||||
ConsoleAppender* m_consoleAppender = nullptr;
|
||||
RollingFileAppender* m_rollingFileAppender = nullptr;
|
||||
JournalAppender* m_journalAppender = nullptr;
|
||||
|
||||
DLogManager *q_ptr = nullptr;
|
||||
Q_DECLARE_PUBLIC(DLogManager)
|
||||
|
||||
};
|
||||
/*!
|
||||
@~english
|
||||
\class Dtk::Core::DLogManager
|
||||
|
@ -35,30 +57,34 @@ static void appendOrganizationAndApp(QString &path)
|
|||
*/
|
||||
|
||||
DLogManager::DLogManager()
|
||||
:d_ptr(new DLogManagerPrivate(this))
|
||||
{
|
||||
m_format = "%{time}{yyyy-MM-dd, HH:mm:ss.zzz} [%{type:-7}] [%{file:-20} %{function:-35} %{line}] %{message}\n";
|
||||
spdlog::set_automatic_registration(true);
|
||||
spdlog::set_pattern("%v");
|
||||
}
|
||||
|
||||
void DLogManager::initConsoleAppender(){
|
||||
m_consoleAppender = new ConsoleAppender;
|
||||
m_consoleAppender->setFormat(m_format);
|
||||
logger->registerAppender(m_consoleAppender);
|
||||
Q_D(DLogManager);
|
||||
d->m_consoleAppender = new ConsoleAppender;
|
||||
d->m_consoleAppender->setFormat(d->m_format);
|
||||
dlogger->registerAppender(d->m_consoleAppender);
|
||||
}
|
||||
|
||||
void DLogManager::initRollingFileAppender(){
|
||||
m_rollingFileAppender = new RollingFileAppender(getlogFilePath());
|
||||
m_rollingFileAppender->setFormat(m_format);
|
||||
m_rollingFileAppender->setLogFilesLimit(5);
|
||||
m_rollingFileAppender->setDatePattern(RollingFileAppender::DailyRollover);
|
||||
logger->registerAppender(m_rollingFileAppender);
|
||||
Q_D(DLogManager);
|
||||
d->m_rollingFileAppender = new RollingFileAppender(getlogFilePath());
|
||||
d->m_rollingFileAppender->setFormat(d->m_format);
|
||||
d->m_rollingFileAppender->setLogFilesLimit(5);
|
||||
d->m_rollingFileAppender->setDatePattern(RollingFileAppender::DailyRollover);
|
||||
dlogger->registerAppender(d->m_rollingFileAppender);
|
||||
}
|
||||
|
||||
|
||||
void DLogManager::initJournalAppender()
|
||||
{
|
||||
#if (defined BUILD_WITH_SYSTEMD && defined Q_OS_LINUX)
|
||||
m_journalAppender = new JournalAppender();
|
||||
logger->registerAppender(m_journalAppender);
|
||||
Q_D(DLogManager);
|
||||
d->m_journalAppender = new JournalAppender();
|
||||
dlogger->registerAppender(d->m_journalAppender);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -101,7 +127,7 @@ QString DLogManager::getlogFilePath()
|
|||
{
|
||||
//No longer set the default log path (and mkdir) when constructing now, instead set the default value if it's empty when getlogFilePath is called.
|
||||
//Fix the problem that the log file is still created in the default path when the log path is set manually.
|
||||
if (DLogManager::instance()->m_logPath.isEmpty()) {
|
||||
if (DLogManager::instance()->d_func()->m_logPath.isEmpty()) {
|
||||
if (DStandardPaths::homePath().isEmpty()) {
|
||||
qWarning() << "Unable to locate the cache directory, cannot acquire home directory, and the log will not be written to file..";
|
||||
return QString();
|
||||
|
@ -113,10 +139,10 @@ QString DLogManager::getlogFilePath()
|
|||
if (!QDir(cachePath).exists()) {
|
||||
QDir(cachePath).mkpath(cachePath);
|
||||
}
|
||||
DLogManager::instance()->m_logPath = DLogManager::instance()->joinPath(cachePath, QString("%1.log").arg(qApp->applicationName()));
|
||||
instance()->d_func()->m_logPath = instance()->joinPath(cachePath, QString("%1.log").arg(qApp->applicationName()));
|
||||
}
|
||||
|
||||
return QDir::toNativeSeparators(DLogManager::instance()->m_logPath);
|
||||
return QDir::toNativeSeparators(DLogManager::instance()->d_func()->m_logPath);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -131,13 +157,13 @@ void DLogManager::setlogFilePath(const QString &logFilePath)
|
|||
if (info.exists() && !info.isFile())
|
||||
qWarning() << "invalid file path:" << logFilePath << " is not a file";
|
||||
else
|
||||
DLogManager::instance()->m_logPath = logFilePath;
|
||||
DLogManager::instance()->d_func()->m_logPath = logFilePath;
|
||||
}
|
||||
|
||||
void DLogManager::setLogFormat(const QString &format)
|
||||
{
|
||||
//m_format = "%{time}{yyyy-MM-dd, HH:mm:ss.zzz} [%{type:-7}] [%{file:-20} %{function:-35} %{line}] %{message}\n";
|
||||
DLogManager::instance()->m_format = format;
|
||||
DLogManager::instance()->d_func()->m_format = format;
|
||||
}
|
||||
|
||||
QString DLogManager::joinPath(const QString &path, const QString &fileName){
|
||||
|
@ -147,7 +173,7 @@ QString DLogManager::joinPath(const QString &path, const QString &fileName){
|
|||
|
||||
DLogManager::~DLogManager()
|
||||
{
|
||||
|
||||
spdlog::shutdown();
|
||||
}
|
||||
|
||||
DCORE_END_NAMESPACE
|
||||
|
|
|
@ -26,9 +26,9 @@ DCORE_BEGIN_NAMESPACE
|
|||
|
||||
/*!
|
||||
@~english
|
||||
\macro Dtk::Core::logger
|
||||
\macro Dtk::Core::dlogger
|
||||
\relates Dtk::Core::Logger
|
||||
\keyword Dtk::Core::logger
|
||||
\keyword Dtk::Core::dlogger
|
||||
|
||||
@brief Macro returning the current instance of Logger object
|
||||
|
||||
|
@ -38,7 +38,7 @@ DCORE_BEGIN_NAMESPACE
|
|||
Example:
|
||||
\code
|
||||
ConsoleAppender* consoleAppender = new ConsoleAppender;
|
||||
logger->registerAppender(consoleAppender);
|
||||
dlogger->registerAppender(consoleAppender);
|
||||
\endcode
|
||||
|
||||
@sa Dtk::Core::Logger::globalInstance()
|
||||
|
@ -248,7 +248,7 @@ DCORE_BEGIN_NAMESPACE
|
|||
\relates Dtk::Core::Logger
|
||||
\keyword Dtk::Core::dCategory()
|
||||
|
||||
@brief Create logger instance inside your custom class to log all messages to the specified \a category
|
||||
@brief Create dlogger instance inside your custom class to log all messages to the specified \a category
|
||||
|
||||
This macro is used to pass all log messages inside your custom class to the specific \a category.
|
||||
You must include this macro inside your class declaration (similarly to the Q_OBJECT macro).
|
||||
|
@ -258,8 +258,8 @@ DCORE_BEGIN_NAMESPACE
|
|||
Thus, any call to loggerInstance() (for example, inside dTrace() macro) will return the local Logger object,
|
||||
so any logging message will be directed to the default category.
|
||||
|
||||
@note This macro does not register any appender to the newly created logger instance. You should register
|
||||
logger appenders manually, inside your class.
|
||||
@note This macro does not register any appender to the newly created dlogger instance. You should register
|
||||
dlogger appenders manually, inside your class.
|
||||
|
||||
Usage example:
|
||||
\code
|
||||
|
@ -272,7 +272,7 @@ DCORE_BEGIN_NAMESPACE
|
|||
|
||||
CustomClass::CustomClass(QObject* parent) : QObject(parent)
|
||||
{
|
||||
logger->registerAppender(new FileAppender("custom_category_log"));
|
||||
dlogger->registerAppender(new FileAppender("custom_category_log"));
|
||||
dTrace() << "Trace to the custom category log";
|
||||
}
|
||||
\endcode
|
||||
|
@ -289,13 +289,13 @@ DCORE_BEGIN_NAMESPACE
|
|||
\relates Dtk::Core::Logger
|
||||
\keyword Dtk::Core::dGlobalCategory()
|
||||
|
||||
@brief Create logger instance inside your custom class to log all messages both to the specified \a category and to
|
||||
the global logger instance.
|
||||
@brief Create dlogger instance inside your custom class to log all messages both to the specified \a category and to
|
||||
the global dlogger instance.
|
||||
|
||||
This macro is similar to dCategory(), but also passes all log messages to the global logger instance appenders.
|
||||
It is equal to defining the local \a category logger using dCategory macro and calling:
|
||||
This macro is similar to dCategory(), but also passes all log messages to the global dlogger instance appenders.
|
||||
It is equal to defining the local \a category dlogger using dCategory macro and calling:
|
||||
\code
|
||||
logger->logToGlobalInstance(logger->defaultCategory(), true);
|
||||
dlogger->logToGlobalInstance(dlogger->defaultCategory(), true);
|
||||
\endcode
|
||||
|
||||
@sa Dtk::Core::dCategory
|
||||
|
@ -423,13 +423,13 @@ DCORE_BEGIN_NAMESPACE
|
|||
|
||||
@brief Very simple but rather powerful component which may be used for logging your application activities.
|
||||
|
||||
Global logger instance created on a first access to it (e.g. registering appenders, calling a dDebug() macro
|
||||
Global dlogger instance created on a first access to it (e.g. registering appenders, calling a dDebug() macro
|
||||
etc.) registers itself as a Qt default message handler and captures all the qDebug/dWarning/qCritical output.
|
||||
|
||||
@note Qt 4 qDebug set of macro doesn't support capturing source function name, file name or line number so we
|
||||
recommend to use dDebug() and other Logger macros instead.
|
||||
|
||||
@sa Dtk::Core::logger
|
||||
@sa Dtk::Core::dlogger
|
||||
*/
|
||||
|
||||
class LogDevice : public QIODevice
|
||||
|
@ -483,21 +483,12 @@ private:
|
|||
const char *m_category;
|
||||
};
|
||||
|
||||
// Forward declarations
|
||||
//static void cleanupLoggerGlobalInstance();
|
||||
|
||||
//#if QT_VERSION >= 0x050000
|
||||
//static void qtLoggerMessageHandler(QtMsgType, const QMessageLogContext& context, const QString &msg);
|
||||
//#else
|
||||
//static void qtLoggerMessageHandler(QtMsgType type, const char *msg);
|
||||
//#endif
|
||||
|
||||
/*!
|
||||
@~english
|
||||
\internal
|
||||
|
||||
LoggerPrivate class implements the Singleton pattern in a thread-safe way. It contains a static pointer to the
|
||||
global logger instance protected by QReadWriteLock
|
||||
global dlogger instance protected by QReadWriteLock
|
||||
*/
|
||||
class LoggerPrivate
|
||||
{
|
||||
|
@ -582,8 +573,8 @@ static void qtLoggerMessageHandler(QtMsgType type, const char *msg)
|
|||
@~english
|
||||
@brief Construct the instance of Logger.
|
||||
|
||||
If you're only using one global instance of logger you wouldn't probably need to use this constructor manually.
|
||||
Consider using [logger](@ref logger) macro instead to access the logger instance
|
||||
If you're only using one global instance of dlogger you wouldn't probably need to use this constructor manually.
|
||||
Consider using [dlogger](@ref dlogger) macro instead to access the dlogger instance
|
||||
*/
|
||||
Logger::Logger()
|
||||
: d_ptr(new LoggerPrivate)
|
||||
|
@ -594,10 +585,10 @@ Logger::Logger()
|
|||
|
||||
/*!
|
||||
@~english
|
||||
@brief Construct the instance of Logger and set logger default category.
|
||||
@brief Construct the instance of Logger and set dlogger default category.
|
||||
|
||||
If you're only using one global instance of logger you wouldn't probably need to use this constructor manually.
|
||||
Consider using logger macro instead to access the logger instance and call setDefaultCategory method.
|
||||
If you're only using one global instance of dlogger you wouldn't probably need to use this constructor manually.
|
||||
Consider using dlogger macro instead to access the dlogger instance and call setDefaultCategory method.
|
||||
|
||||
@sa Logger()
|
||||
@sa setDefaultCategory()
|
||||
|
@ -612,7 +603,7 @@ Logger::Logger(const QString &defaultCategory)
|
|||
@~english
|
||||
@brief Destroy the instance of Logger.
|
||||
|
||||
You probably wouldn't need to use this function directly. Global instance of logger will be destroyed automatically
|
||||
You probably wouldn't need to use this function directly. Global instance of dlogger will be destroyed automatically
|
||||
at the end of your QCoreApplication execution
|
||||
*/
|
||||
Logger::~Logger()
|
||||
|
@ -642,9 +633,9 @@ Logger::~Logger()
|
|||
@~english
|
||||
@brief Returns the global instance of Logger.
|
||||
|
||||
In a most cases you shouldn't use this function directly. Consider using [logger](@ref logger) macro instead.
|
||||
In a most cases you shouldn't use this function directly. Consider using [dlogger](@ref dlogger) macro instead.
|
||||
|
||||
@sa Dtk::Core::logger
|
||||
@sa Dtk::Core::dlogger
|
||||
*/
|
||||
Logger *Logger::globalInstance()
|
||||
{
|
||||
|
@ -773,7 +764,7 @@ void Logger::registerAppender(AbstractAppender *appender)
|
|||
writing to the default category, or using special dCDebug(), dCWarning() etc. macros),
|
||||
Logger writes the log message only to the list of registered category appenders.
|
||||
|
||||
You can call logToGlobalInstance() to pass all category log messages to the global logger instance appenders
|
||||
You can call logToGlobalInstance() to pass all category log messages to the global dlogger instance appenders
|
||||
(registered using registerAppender()).
|
||||
If no category appenders with specific name was registered to the Logger,
|
||||
it falls back to logging into the \c std::cerr STL stream, both with simple warning message.
|
||||
|
@ -805,16 +796,16 @@ void Logger::registerCategoryAppender(const QString &category, AbstractAppender
|
|||
#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0)
|
||||
/*!
|
||||
@~english
|
||||
@brief Links some logging category with the global logger instance appenders.
|
||||
@brief Links some logging category with the global dlogger instance appenders.
|
||||
|
||||
If set to true, all log messages to the specified category appenders will also be written to the global logger instance appenders,
|
||||
If set to true, all log messages to the specified category appenders will also be written to the global dlogger instance appenders,
|
||||
registered using registerAppender().
|
||||
|
||||
By default, all messages to the specific category are written only to the specific category appenders
|
||||
(registered using registerCategoryAppender()).
|
||||
|
||||
@param category Category name
|
||||
@param logToGlobal Link or onlink the category from global logger instance appender
|
||||
@param logToGlobal Link or onlink the category from global dlogger instance appender
|
||||
|
||||
@sa globalInstance
|
||||
@sa registerAppender
|
||||
|
@ -831,7 +822,7 @@ void Logger::logToGlobalInstance(const QString &category, bool logToGlobal)
|
|||
@~english
|
||||
@brief Sets default logging category.
|
||||
|
||||
All log messages to this category appenders will also be written to general logger instance appenders (registered
|
||||
All log messages to this category appenders will also be written to general dlogger instance appenders (registered
|
||||
using [registerAppender](@ref registerAppender) method), and vice versa.
|
||||
In particular, any calls to the dDebug() macro will be treated as category logging,
|
||||
so you needn't to specify category name using dCDebug() macro.
|
||||
|
@ -1001,13 +992,13 @@ void Logger::write(const QDateTime &time, Logger::LogLevel level, const char *fi
|
|||
} else {
|
||||
static bool noAppendersWarningShown = false;
|
||||
if (!noAppendersWarningShown) {
|
||||
std::cerr << "No appenders registered with logger" << std::endl;
|
||||
std::cerr << "No appenders registered with dlogger" << std::endl;
|
||||
noAppendersWarningShown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// local logger instances send category messages to the global instance
|
||||
// local dlogger instances send category messages to the global instance
|
||||
if (!logCategory.isNull() && !isGlobalInstance)
|
||||
globalInstance()->write(time, level, file, line, func, logCategory.toLatin1(), msg, true);
|
||||
|
||||
|
@ -1023,61 +1014,45 @@ void Logger::write(const QDateTime &time, Logger::LogLevel level, const char *fi
|
|||
}
|
||||
}
|
||||
|
||||
void CuteMessageLogger::write(const char *msg, ...) const
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, msg);
|
||||
m_l->write(m_level, m_file, m_line, m_function, m_category, QString::vasprintf(msg, va));
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void CuteMessageLogger::write(const QString &msg) const
|
||||
{
|
||||
m_l->write(m_level, m_file, m_line, m_function, m_category, msg);
|
||||
}
|
||||
|
||||
QDebug CuteMessageLogger::write() const
|
||||
{
|
||||
return m_l->write(m_level, m_file, m_line, m_function, m_category);
|
||||
}
|
||||
|
||||
void LoggerTimingHelper::start(const char *msg, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, msg);
|
||||
m_block = QString::vasprintf(msg, va);
|
||||
va_end(va);
|
||||
|
||||
m_time.start();
|
||||
}
|
||||
|
||||
void LoggerTimingHelper::start(const QString &msg)
|
||||
{
|
||||
m_block = msg;
|
||||
m_time.start();
|
||||
}
|
||||
|
||||
LoggerTimingHelper::~LoggerTimingHelper()
|
||||
{
|
||||
QString message;
|
||||
if (m_block.isEmpty())
|
||||
message = QString(QLatin1String("Function %1 finished in ")).arg(AbstractStringAppender::stripFunctionName(m_function));
|
||||
else
|
||||
message = QString(QLatin1String("\"%1\" finished in ")).arg(m_block);
|
||||
|
||||
int elapsed = m_time.elapsed();
|
||||
if (elapsed >= 10000)
|
||||
message += QString(QLatin1String("%1 s.")).arg(elapsed / 1000);
|
||||
else
|
||||
message += QString(QLatin1String("%1 ms.")).arg(elapsed);
|
||||
|
||||
m_logger->write(m_logLevel, m_file, m_line, m_function, nullptr, message);
|
||||
}
|
||||
|
||||
Logger* loggerInstance()
|
||||
{
|
||||
return Logger::globalInstance();
|
||||
}
|
||||
|
||||
class D_DECL_DEPRECATED CuteMessageLogger
|
||||
{
|
||||
Q_DISABLE_COPY(CuteMessageLogger)
|
||||
public:
|
||||
Q_DECL_CONSTEXPR CuteMessageLogger(Logger *, Logger::LogLevel ,
|
||||
const char *, int , const char *)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Q_DECL_CONSTEXPR CuteMessageLogger(Logger *l, Logger::LogLevel, const char *,
|
||||
int, const char *, const char *)
|
||||
{
|
||||
}
|
||||
void write(const char *msg, ...) const;
|
||||
void write(const QString &msg) const;
|
||||
QDebug write() const;
|
||||
|
||||
};
|
||||
|
||||
void CuteMessageLogger::write(const char */*msg*/, ...) const
|
||||
{
|
||||
write();
|
||||
}
|
||||
|
||||
void CuteMessageLogger::write(const QString &/*msg*/) const
|
||||
{
|
||||
write();
|
||||
}
|
||||
|
||||
QDebug CuteMessageLogger::write() const
|
||||
{
|
||||
return QDebug(QtWarningMsg) << "DEPRECATED! rebuild your application with lastest DtkCore";
|
||||
}
|
||||
|
||||
DCORE_END_NAMESPACE
|
||||
#include "Logger.moc"
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
// Local
|
||||
#include "win32/OutputDebugAppender.h"
|
||||
|
||||
#include <spdlog/sinks/msvc_sink.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
// STL
|
||||
#include <windows.h>
|
||||
|
||||
|
@ -41,8 +44,16 @@ void OutputDebugAppender::append(const QDateTime &time,
|
|||
const QString &category,
|
||||
const QString &msg)
|
||||
{
|
||||
QString s = formattedString(time, level, file, line, function, category, msg);
|
||||
OutputDebugStringW((LPCWSTR) s.utf16());
|
||||
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
|
||||
|
|
|
@ -47,10 +47,10 @@ int main(int argc, char* argv[])
|
|||
// 1.3 log to stdout and file
|
||||
// DLogManager::registerFileAppender();
|
||||
// DLogManager::registerConsoleAppender();
|
||||
// 2 Register your own logger format;
|
||||
// 2 Register your own dlogger format;
|
||||
// ConsoleAppender* consoleAppender = new ConsoleAppender;
|
||||
// consoleAppender->setFormat("[%{type:-7}] <%{Function}> %{message}\n");
|
||||
// logger->registerAppender(consoleAppender);
|
||||
// dlogger->registerAppender(consoleAppender);
|
||||
dInfo("Starting the application");
|
||||
int result = 1;
|
||||
dWarning() << "Something went wrong." << "Result code is" << result;
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
|
||||
#include "RollingFileAppender.h"
|
||||
|
||||
DCORE_BEGIN_NAMESPACE
|
||||
#include "rollingfilesink_p.h"
|
||||
|
||||
DCORE_BEGIN_NAMESPACE
|
||||
extern std::string loggerName(const QFile &logFile);
|
||||
/*!
|
||||
@~english
|
||||
@class Dtk::Core::RollingFileAppender
|
||||
|
@ -28,23 +30,15 @@ DCORE_BEGIN_NAMESPACE
|
|||
*/
|
||||
|
||||
RollingFileAppender::RollingFileAppender(const QString &fileName)
|
||||
: FileAppender(fileName),
|
||||
m_logFilesLimit(0),
|
||||
m_logSizeLimit(1024 * 1024 * 20)
|
||||
: 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)
|
||||
{
|
||||
|
||||
if (!m_rollOverTime.isNull() && QDateTime::currentDateTime() > m_rollOverTime)
|
||||
rollOver();
|
||||
|
||||
if (size()> m_logSizeLimit)
|
||||
rollOver();
|
||||
|
||||
FileAppender::append(time, level, file, line , func, category, msg);
|
||||
}
|
||||
|
||||
|
@ -62,177 +56,52 @@ QString RollingFileAppender::datePatternString() const
|
|||
|
||||
void RollingFileAppender::setDatePattern(DatePattern datePattern)
|
||||
{
|
||||
setDatePatternString(QLatin1String("'.'yyyy-MM-dd-hh-mm-ss-zzz"));
|
||||
|
||||
QMutexLocker locker(&m_rollingMutex);
|
||||
m_frequency = datePattern;
|
||||
|
||||
computeRollOverTime();
|
||||
}
|
||||
|
||||
void RollingFileAppender::setDatePattern(const QString &datePattern)
|
||||
void RollingFileAppender::setDatePattern(const QString &/*datePattern*/)
|
||||
{
|
||||
setDatePatternString(datePattern);
|
||||
computeFrequency();
|
||||
|
||||
computeRollOverTime();
|
||||
}
|
||||
|
||||
void RollingFileAppender::setDatePatternString(const QString &datePatternString)
|
||||
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, nowTime);
|
||||
m_rollOverTime = start.addSecs(60);
|
||||
if (auto *fs = get_sink<rolling_file_sink_st>(loggerName(fileName()))){
|
||||
return fs->set_interval(RollingInterval(m_frequency));
|
||||
}
|
||||
break;
|
||||
case HourlyRollover:
|
||||
{
|
||||
start = QDateTime(nowDate, nowTime);
|
||||
m_rollOverTime = start.addSecs(60*60);
|
||||
}
|
||||
break;
|
||||
case HalfDailyRollover:
|
||||
{
|
||||
int hour = nowTime.hour();
|
||||
if (hour >= 12)
|
||||
hour = 12;
|
||||
else
|
||||
hour = 0;
|
||||
start = QDateTime(nowDate, nowTime);
|
||||
m_rollOverTime = start.addSecs(60*60*12);
|
||||
}
|
||||
break;
|
||||
case DailyRollover:
|
||||
{
|
||||
start = QDateTime(nowDate, nowTime);
|
||||
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, nowTime).addDays(-1 * day);
|
||||
m_rollOverTime = start.addDays(7);
|
||||
}
|
||||
break;
|
||||
case MonthlyRollover:
|
||||
{
|
||||
start = QDateTime(QDate(nowDate.year(), nowDate.month(), 1), nowTime);
|
||||
m_rollOverTime = start.addMonths(1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT_X(false, "DailyRollingFileAppender::computeInterval()", "Invalid datePattern constant");
|
||||
m_rollOverTime = QDateTime::fromSecsSinceEpoch(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;
|
||||
|
||||
if (auto *fs = get_sink<rolling_file_sink_st>(loggerName(fileName()))){
|
||||
return fs->set_max_files(std::size_t(limit));
|
||||
}
|
||||
}
|
||||
|
||||
int RollingFileAppender::logFilesLimit() const
|
||||
|
@ -245,6 +114,10 @@ void RollingFileAppender::setLogSizeLimit(int limit)
|
|||
{
|
||||
QMutexLocker locker(&m_rollingMutex);
|
||||
m_logSizeLimit = limit;
|
||||
|
||||
if (auto *fs = get_sink<rolling_file_sink_st>(loggerName(fileName()))){
|
||||
return fs->set_max_size(std::size_t(limit));
|
||||
}
|
||||
}
|
||||
|
||||
qint64 RollingFileAppender::logSizeLimit() const
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
// 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
|
|
@ -9,6 +9,8 @@ set(LOG_SOURCE
|
|||
${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)
|
||||
|
|
|
@ -0,0 +1,307 @@
|
|||
// 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,9,0)
|
||||
std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::memory_buffer, fmt::wmemory_buffer>::type w;
|
||||
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
|
|
@ -37,10 +37,3 @@ TEST(ut_DLogManager, testSetInvalidLogPath)
|
|||
// set log file path to a dir is not supported
|
||||
ASSERT_NE(DLogManager::getlogFilePath(), tmp);
|
||||
}
|
||||
|
||||
TEST(ut_DLogManager, format)
|
||||
{
|
||||
QString fmt = "%{time}{yyyy-MM-dd, HH:mm:ss.zzz} %{message}\n";
|
||||
DLogManager::setLogFormat(fmt);
|
||||
ASSERT_EQ(DLogManager::instance()->m_format, fmt);
|
||||
}
|
||||
|
|
|
@ -5,13 +5,23 @@
|
|||
#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
|
||||
|
||||
static QString tmpFileName()
|
||||
{
|
||||
QTemporaryFile tmp;
|
||||
tmp.open();
|
||||
return tmp.fileName();
|
||||
}
|
||||
|
||||
class ut_Logger: public testing::Test
|
||||
{
|
||||
protected:
|
||||
|
@ -87,8 +97,7 @@ TEST_F(ut_Logger, testGlobalInstance)
|
|||
TEST_F(ut_Logger, testRegisterAppender)
|
||||
{
|
||||
Logger* gLogger = Logger::globalInstance();
|
||||
|
||||
FileAppender *fileAppener = new FileAppender("/tmp/log");
|
||||
FileAppender *fileAppener = new FileAppender(tmpFileName());
|
||||
if (fileAppener->detailsLevel() > Logger::Trace)
|
||||
fileAppener->setDetailsLevel(Logger::Trace);
|
||||
gLogger->registerAppender(fileAppener);
|
||||
|
@ -109,8 +118,8 @@ TEST_F(ut_Logger, testRegisterAppender)
|
|||
if (rollingFileAppender->detailsLevel() > Logger::Trace)
|
||||
rollingFileAppender->setDetailsLevel(Logger::Trace);
|
||||
gLogger->registerAppender(rollingFileAppender);
|
||||
rollingFileAppender->setDatePattern("'.'yyyy-MM-dd-hh-mm");
|
||||
ASSERT_TRUE(rollingFileAppender->datePatternString() == "'.'yyyy-MM-dd-hh-mm");
|
||||
// rollingFileAppender->setDatePattern("'.'yyyy-MM-dd-hh-mm");
|
||||
// ASSERT_TRUE(rollingFileAppender->datePatternString() == "'.'yyyy-MM-dd-hh-mm");
|
||||
rollingFileAppender->setLogFilesLimit(2);
|
||||
ASSERT_TRUE(rollingFileAppender->logFilesLimit() == 2);
|
||||
rollingFileAppender->setDatePattern(RollingFileAppender::MinutelyRollover);
|
||||
|
@ -127,19 +136,19 @@ TEST_F(ut_Logger, testRegisterAppender)
|
|||
TEST_F(ut_Logger, testRegisterCategoryAppender)
|
||||
{
|
||||
Logger* gLogger = Logger::globalInstance();
|
||||
FileAppender *fileAppener = new FileAppender("/tmp/log");
|
||||
FileAppender *fileAppener = new FileAppender(tmpFileName());
|
||||
if (fileAppener->detailsLevel() > Logger::Trace)
|
||||
fileAppener->setDetailsLevel(Logger::Trace);
|
||||
gLogger->registerCategoryAppender("test", fileAppener);
|
||||
gLogger->registerCategoryAppender("testRegisterCategoryAppender", fileAppener);
|
||||
ASSERT_TRUE(fileAppener->size() == 0);
|
||||
dCDebug("test") << "testRegisterAppender";
|
||||
dCDebug("testRegisterCategoryAppender") << "testRegisterCategoryAppender";
|
||||
ASSERT_TRUE(fileAppener->size() != 0);
|
||||
}
|
||||
|
||||
TEST_F(ut_Logger, testLogToGlobalInstance)
|
||||
{
|
||||
Logger* gLogger = Logger::globalInstance();
|
||||
FileAppender *fileAppener = new FileAppender("/tmp/log");
|
||||
FileAppender *fileAppener = new FileAppender(tmpFileName());
|
||||
if (fileAppener->detailsLevel() > Logger::Trace)
|
||||
fileAppener->setDetailsLevel(Logger::Trace);
|
||||
gLogger->registerAppender(fileAppener);
|
||||
|
@ -151,8 +160,8 @@ TEST_F(ut_Logger, testLogToGlobalInstance)
|
|||
|
||||
TEST_F(ut_Logger, testSetDefaultCategory)
|
||||
{
|
||||
m_logger->setDefaultCategory("test");
|
||||
ASSERT_EQ(m_logger->defaultCategory(), "test");
|
||||
m_logger->setDefaultCategory("testSetDefaultCategory");
|
||||
ASSERT_EQ(m_logger->defaultCategory(), "testSetDefaultCategory");
|
||||
}
|
||||
|
||||
TEST_F(ut_Logger, testDefaultCategory)
|
||||
|
|
Loading…
Reference in New Issue