Qt spdlog日志模塊的使用詳解
版本
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應(yīng)用程序開發(fā)中,良好的日志系統(tǒng)至關(guān)重要。本文將介紹如何使用spdlog 1.5.0創(chuàng)建滿足以下要求的日志系統(tǒng):
- 自定義文件名格式:yyyyMMdd_hhmmss_毫秒.log,不使用spdlog提供的日志輪轉(zhuǎn)功能
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_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 兼容實現(xiàn) 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); // 設(shè)置默認日志格式 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); // 初始化日志系統(tǒng) LogManager::instance().initialize("logs", "MyAppTest"); // 連接關(guān)閉信號進行額外清理 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(); }
到此這篇關(guān)于Qt spdlog日志模塊的使用的文章就介紹到這了,更多相關(guān)Qt spdlog日志模塊內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
c++中為什么可以通過指針或引用實現(xiàn)多態(tài)詳解
這篇文章主要給大家介紹了關(guān)于c++中為何可以通過指針或引用實現(xiàn)多態(tài),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-04-04用C實現(xiàn)PHP擴展 Fetch_Url 類數(shù)據(jù)抓取的方法
該擴展是基于libcurl基礎(chǔ)實現(xiàn)的網(wǎng)頁數(shù)據(jù)抓取2013-04-04