Version
spdlog version: 1.5.0
The use of version 1.5.0 is mainly based on the following considerations: compatible with version Qt5 and compatible with C++11.
spdlog 1.5.0 download address: /gabime/spdlog/releases/tag/v1.5.0
summary
In Qt application development, a good logging system is crucial. This article will introduce how to use spdlog 1.5.0 to create a log system that meets the following requirements:
- Custom file name format: yyyyMMdd_hhmmss_ms.log, do not use the log rotation function provided by spdlog
spdlog::sinks::rotating_file_sink_mt, using custom custom_rotating_file_sink;
- Keep the last 10 log files, each log file size is limited to 1MB.
example
document
#ifndef LOGMANAGER_H #define LOGMANAGER_H #include <QObject> #include <memory> #include <spdlog/> 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, ().c_str(), args...); } } // Convenient method 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(); }; // Log macro definition#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
document
#include "" #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> // Replace the C++11 compatible implementation of std::filesystemnamespace 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() + () > max_size_) { rotate_(); } file_helper_.write(formatted); } void flush_() override { file_helper_.flush(); } private: std::string gen_filename() { QDateTime now = QDateTime::currentDateTime(); QString timeStr = ("yyyyMMddhhmmss"); // Add milliseconds part (3 digits) int ms = ().msec(); timeStr += QString("_%1").arg(ms, 3, 10, QLatin1Char('0')); return base_filename_ + "_" + () + ".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 = (QStringList() << (base_name + "_*.log"), QDir::Files, QDir::Time); // Delete the oldest file while (() >= static_cast<int>(max_files_)) { QFile::remove(().absoluteFilePath()); (); } } 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) { // Connect Qt exit signal connect(qApp, &QCoreApplication::aboutToQuit, this, &LogManager::onAboutToQuit); // Handle exception signals 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; } // Make sure the log directory exists QDir().mkpath(logDir); std::string base_filename = QDir(logDir).absoluteFilePath(appName).toStdString(); m_logger = createCustomLogger(base_filename, maxFileSize, maxFiles); // Set the default log format 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:" << (); } } 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; }
document
#include <QCoreApplication> #include "" #include <QTimer> #include <QDebug> int main(int argc, char* argv[]) { QCoreApplication a(argc, argv); // Initialize the log system LogManager::instance().initialize("logs", "MyAppTest"); // Connect the shutdown signal for additional cleaning 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 (); }
This is the end of this article about the use of Qt spdlog log module. For more related contents of Qt spdlog log module, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!