it编程 > 编程语言 > C/C++

Qt spdlog日志模块的使用详解

33人参与 2025-04-12 C/C++

版本

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创建满足以下要求的日志系统:

spdlog::sinks::rotating_file_sink_mt,采用自定义custom_rotating_file_sink;

例子

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_h

logmanager.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日志模块内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)
打赏 微信扫一扫 微信扫一扫

您想发表意见!!点此发布评论

推荐阅读

C++ vector的常见用法超详细讲解

04-12

在C++中实现高效的数组原地轮转的方法总结

04-12

如何高效移除C++关联容器中的元素

04-12

dev c++ 怎么添加外部库

04-08

c++ 函数重载的规则是什么

04-08

基于PyQt5实现的Windows定时关机工具

04-14

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论