版本
spdlog版本:1.5.0
采用1.5.0版本主要基于以下考虑:兼容qt5.9.x版本和兼容c++11。
spdlog 1.5.0下载地址:https://github.com/gabime/spdlog/releases/tag/v1.5.0
摘要
在qt应用程序开发中,良好的日志系统至关重要。本文将介绍如何使用spdlog 1.5.0创建满足以下要求的日志系统:
- 自定义文件名格式:yyyymmdd_hhmmss_毫秒.log,不使用spdlog提供的日志轮转功能
spdlog::sinks::rotating_file_sink_mt,采用自定义custom_rotating_file_sink;
- 保留最近10个日志文件,每个日志文件大小限制为1mb。
例子
logmanager.h文件
#ifndef logmanager_h
#define logmanager_h
#include <qobject>
#include <memory>
#include <spdlog/spdlog.h>
class logmanager : public qobject
{
q_object
public:
static logmanager& instance();
void initialize(const qstring& logdir = "logs",
const qstring& appname = "app",
size_t maxfilesize = 1024 * 1024, // 1mb
size_t maxfiles = 10);
void shutdown();
template<typename... args>
static void log(spdlog::level::level_enum level, const qstring& message, args... args)
{
if (instance().m_logger)
{
instance().m_logger->log(level, message.tostdstring().c_str(), args...);
}
}
// 便捷方法
static void trace(const qstring& message)
{
log(spdlog::level::trace, message);
}
static void debug(const qstring& message)
{
log(spdlog::level::debug, message);
}
static void info(const qstring& message)
{
log(spdlog::level::info, message);
}
static void warn(const qstring& message)
{
log(spdlog::level::warn, message);
}
static void error(const qstring& message)
{
log(spdlog::level::err, message);
}
static void critical(const qstring& message)
{
log(spdlog::level::critical, message);
}
private:
logmanager(qobject* parent = nullptr);
~logmanager();
std::shared_ptr<spdlog::logger> createcustomlogger(const std::string& base_filename,
size_t max_size,
size_t max_files);
std::shared_ptr<spdlog::logger> m_logger;
std::atomic<bool> m_shuttingdown{false};
signals:
void abouttoshutdown();
private slots:
void onabouttoquit();
};
// 日志宏定义
#define log_trace(...) logmanager::log(spdlog::level::trace, __va_args__)
#define log_debug(...) logmanager::log(spdlog::level::debug, __va_args__)
#define log_info(...) logmanager::log(spdlog::level::info, __va_args__)
#define log_warn(...) logmanager::log(spdlog::level::warn, __va_args__)
#define log_error(...) logmanager::log(spdlog::level::err, __va_args__)
#define log_critical(...) logmanager::log(spdlog::level::critical, __va_args__)
#endif // logmanager_hlogmanager.cpp文件
#include "logmanager.h"
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/file_helper.h>
#include <mutex>
#include <chrono>
#include <iomanip>
#include <sstream>
#include <vector>
#include <algorithm>
#include <qdir>
#include <qfileinfo>
#include <qdatetime>
#include <qcoreapplication>
#include <csignal>
#include <qdebug>
// 替换 std::filesystem 的 c++11 兼容实现
namespace spdlog
{
class custom_rotating_file_sink : public spdlog::sinks::base_sink<std::mutex>
{
public:
custom_rotating_file_sink(const std::string& base_filename,
std::size_t max_size,
std::size_t max_files)
: base_filename_(base_filename),
max_size_(max_size),
max_files_(max_files)
{
file_helper_.open(gen_filename());
}
protected:
void sink_it_(const spdlog::details::log_msg& msg) override
{
spdlog::memory_buf_t formatted;
formatter_->format(msg, formatted);
if (file_helper_.size() + formatted.size() > max_size_)
{
rotate_();
}
file_helper_.write(formatted);
}
void flush_() override
{
file_helper_.flush();
}
private:
std::string gen_filename()
{
qdatetime now = qdatetime::currentdatetime();
qstring timestr = now.tostring("yyyymmddhhmmss");
// 添加毫秒部分(3位)
int ms = now.time().msec();
timestr += qstring("_%1").arg(ms, 3, 10, qlatin1char('0'));
return base_filename_ + "_" + timestr.tostdstring() + ".log";
}
void rotate_()
{
file_helper_.close();
cleanup_old_files();
file_helper_.open(gen_filename());
}
void cleanup_old_files()
{
if (max_files_ == 0) return;
qfileinfo base_info(qstring::fromstdstring(base_filename_));
qdir dir = base_info.absolutedir();
qstring base_name = base_info.filename();
qfileinfolist files = dir.entryinfolist(qstringlist() << (base_name + "_*.log"),
qdir::files, qdir::time);
// 删除最旧的文件
while (files.size() >= static_cast<int>(max_files_))
{
qfile::remove(files.last().absolutefilepath());
files.removelast();
}
}
std::string base_filename_;
std::size_t max_size_;
std::size_t max_files_;
spdlog::details::file_helper file_helper_;
};
} // namespace
logmanager::logmanager(qobject* parent) : qobject(parent)
{
// 连接qt退出信号
connect(qapp, &qcoreapplication::abouttoquit, this, &logmanager::onabouttoquit);
// 处理异常信号
static auto handlesignal = [](int)
{
logmanager::instance().shutdown();
std::_exit(1);
};
std::signal(sigterm, handlesignal);
std::signal(sigsegv, handlesignal);
std::signal(sigint, handlesignal);
std::signal(sigabrt, handlesignal);
}
logmanager::~logmanager()
{
shutdown();
}
logmanager& logmanager::instance()
{
static logmanager instance;
return instance;
}
void logmanager::initialize(const qstring& logdir, const qstring& appname, size_t maxfilesize, size_t maxfiles)
{
if (m_logger)
{
return;
}
// 确保日志目录存在
qdir().mkpath(logdir);
std::string base_filename = qdir(logdir).absolutefilepath(appname).tostdstring();
m_logger = createcustomlogger(base_filename, maxfilesize, maxfiles);
// 设置默认日志格式
m_logger->set_pattern("[%y-%m-%d %h:%m:%s.%e] [%l] [thread %t] %v");
m_logger->set_level(spdlog::level::trace);
spdlog::register_logger(m_logger);
spdlog::set_default_logger(m_logger);
}
void logmanager::shutdown()
{
/*
if (m_logger)
{
spdlog::drop(m_logger->name());
m_logger.reset();
}
spdlog::shutdown();
*/
if (m_shuttingdown) return;
m_shuttingdown = true;
emit abouttoshutdown();
try
{
if (m_logger)
{
m_logger->flush();
spdlog::drop(m_logger->name());
}
spdlog::shutdown();
m_logger.reset();
}
catch (const spdlog::spdlog_ex& ex)
{
qcritical() << "log shutdown error:" << ex.what();
}
}
void logmanager::onabouttoquit()
{
shutdown();
}
std::shared_ptr<spdlog::logger> logmanager::createcustomlogger(const std::string& base_filename,
size_t max_size,
size_t max_files)
{
auto sink = std::make_shared<spdlog::custom_rotating_file_sink>(base_filename, max_size, max_files);
auto logger = std::make_shared<spdlog::logger>("qt_logger", sink);
return logger;
}main.cpp文件
#include <qcoreapplication>
#include "logmanager.h"
#include <qtimer>
#include <qdebug>
int main(int argc, char* argv[])
{
qcoreapplication a(argc, argv);
// 初始化日志系统
logmanager::instance().initialize("logs", "myapptest");
// 连接关闭信号进行额外清理
qobject::connect(&logmanager::instance(), &logmanager::abouttoshutdown, []()
{
log_info("performing final cleanup before shutdown...");
});
for (int i = 0; i < 5000; ++i)
{
log_info("this is a test message to fill up the log file. iteration: {}", i);
}
return a.exec();
}到此这篇关于qt spdlog日志模块的使用的文章就介绍到这了,更多相关qt spdlog日志模块内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论