使用spdlog实现多线程日志管理器
LoggerManager.h
---
#pragma once
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LOGGER_TRACE
#include <memory>
#include <string>
#include <unordered_map>
#include <mutex>
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/rotating_file_sink.h>
#include <spdlog/async.h>
class LoggerManager {
public:
~LoggerManager();
LoggerManager(const LoggerManager&) = delete;
LoggerManager& operator=(const LoggerManager&) = delete;
static LoggerManager& getInstance();
void init();
std::shared_ptr<spdlog::logger> getConsoleLogger();
std::shared_ptr<spdlog::logger> getFileLogger();
std::shared_ptr<spdlog::logger> createConsoleLogger(const std::string& name);
std::shared_ptr<spdlog::logger> createFileLogger(const std::string& name, const std::string& filename,
size_t max_size = 1024 * 1024 * 10, size_t max_files_count = 7, bool rotate_daily = true);
std::shared_ptr<spdlog::logger> getLogger(const std::string& name);
void setLevel(spdlog::level::level_enum level);
void flushAll();
void shutdownAll();
private:
LoggerManager();
template<typename Sink>
void setDetailedFormat(const std::shared_ptr<Sink>& sink) {
// 详细的日志格式: [时间] [线程ID] [日志级别] [日志器名称] 文件名:行号 - 消息
sink->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%t] [%^%l%$] %s:%# %v");
}
bool m_is_inited = false;
std::mutex m_mutex;
std::shared_ptr<spdlog::logger> m_default_console_logger;
std::shared_ptr<spdlog::logger> m_default_file_logger;
std::unordered_map<std::string, std::shared_ptr<spdlog::logger>> m_console_loggers;
std::unordered_map<std::string, std::shared_ptr<spdlog::logger>> m_file_loggers;
};
#define LOG_CONSOLE(...) LoggerManager::getInstance().getConsoleLogger()->info(__VA_ARGS__)
#define LOG_FILE(...) LoggerManager::getInstance().getFileLogger()->info(__VA_ARGS__))
#define SLOG_CONSOLE_TRACE(...) SPDLOG_LOGGER_TRACE(LoggerManager::getInstance().getConsoleLogger(), __VA_ARGS__)
#define SLOG_CONSOLE_DEBUG(...) SPDLOG_LOGGER_DEBUG(LoggerManager::getInstance().getConsoleLogger(), __VA_ARGS__)
#define SLOG_CONSOLE_INFO(...) SPDLOG_LOGGER_INFO(LoggerManager::getInstance().getConsoleLogger(), __VA_ARGS__)
#define SLOG_CONSOLE_WARN(...) SPDLOG_LOGGER_WARN(LoggerManager::getInstance().getConsoleLogger(), __VA_ARGS__)
#define SLOG_CONSOLE_ERROR(...) SPDLOG_LOGGER_ERROR(LoggerManager::getInstance().getConsoleLogger(), __VA_ARGS__)
#define SLOG_CONSOLE_CRITICAL(...) SPDLOG_LOGGER_CRITICAL(LoggerManager::getInstance().getConsoleLogger(), __VA_ARGS__)
#define SLOG_FILE_TRACE(...) SPDLOG_LOGGER_TRACE(LoggerManager::getInstance().getFileLogger(), __VA_ARGS__)
#define SLOG_FILE_DEBUG(...) SPDLOG_LOGGER_DEBUG(LoggerManager::getInstance().getFileLogger(), __VA_ARGS__)
#define SLOG_FILE_INFO(...) SPDLOG_LOGGER_INFO(LoggerManager::getInstance().getFileLogger(), __VA_ARGS__)
#define SLOG_FILE_WARN(...) SPDLOG_LOGGER_WARN(LoggerManager::getInstance().getFileLogger(), __VA_ARGS__)
#define SLOG_FILE_ERROR(...) SPDLOG_LOGGER_ERROR(LoggerManager::getInstance().getFileLogger(), __VA_ARGS__)
#define SLOG_FILE_CRITICAL(...) SPDLOG_LOGGER_CRITICAL(LoggerManager::getInstance().getFileLogger(), __VA_ARGS__)
---
LoggerManager.cpp
---
#include "LoggerManager.h"
#include <chrono>
LoggerManager::LoggerManager()
{
try {
spdlog::flush_every(std::chrono::seconds(5));
spdlog::init_thread_pool(8192, 1); // 初始化异步日志线程池,队列大小为8192,线程数为2
}
catch (const spdlog::spdlog_ex& ex)
{
spdlog::error("异步线程池初始化失败:{}", ex.what());
}
}
LoggerManager::~LoggerManager()
{
shutdownAll();
}
LoggerManager& LoggerManager::getInstance()
{
static LoggerManager instance;
return instance;
}
void LoggerManager::init()
{
try {
if (!m_default_console_logger) {
createConsoleLogger("console");
}
if (!m_default_file_logger) {
createFileLogger("file", "logs/app.log");
}
m_is_inited = true;
}
catch (const spdlog::spdlog_ex& ex)
{
spdlog::error("LoggerManager 初始化失败:{}", ex.what());
}
}
std::shared_ptr<spdlog::logger> LoggerManager::getConsoleLogger()
{
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_default_console_logger) {
return m_default_console_logger;
}
}
createConsoleLogger("console");
return m_default_console_logger;
}
std::shared_ptr<spdlog::logger> LoggerManager::getFileLogger()
{
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_default_file_logger) {
return m_default_file_logger;
}
}
createFileLogger("file", "logs/app.log");
return m_default_file_logger;
}
std::shared_ptr<spdlog::logger> LoggerManager::createConsoleLogger(const std::string& name)
{
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_console_loggers.find(name) != m_console_loggers.end()) {
return m_console_loggers[name];
}
try {
auto sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
setDetailedFormat(sink);
auto logger = std::make_shared<spdlog::logger>(name, sink);
spdlog::register_logger(logger);
if (!m_default_console_logger)
{
m_default_console_logger = logger;
}
m_console_loggers[name] = logger;
return logger;
}
catch (const spdlog::spdlog_ex& ex) {
spdlog::error("创建控制台日志器失败:{}", ex.what());
return nullptr;
}
}
}
std::shared_ptr<spdlog::logger> LoggerManager::createFileLogger(const std::string& name, const std::string& filename, size_t max_size, size_t max_files_count, bool rotate_daily)
{
{
std::lock_guard<std::mutex> lock(m_mutex);
try {
if (rotate_daily) {
auto sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
filename, max_size, max_files_count, true);
setDetailedFormat(sink);
auto logger = std::make_shared<spdlog::logger>(name, sink);
spdlog::register_logger(logger);
if (!m_default_file_logger) {
m_default_file_logger = logger;
}
m_file_loggers[name] = logger;
return logger;
}
else {
auto sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
setDetailedFormat(sink);
auto logger = std::make_shared<spdlog::logger>(name, sink);
spdlog::register_logger(logger);
if (!m_default_file_logger) {
m_default_file_logger = logger;
}
m_file_loggers[name] = logger;
return logger;
}
}
catch (const spdlog::spdlog_ex& ex) {
spdlog::error("创建文件日志器失败:{}", ex.what());
return nullptr;
}
}
}
std::shared_ptr<spdlog::logger> LoggerManager::getLogger(const std::string& name)
{
{
std::lock_guard<std::mutex> lock(m_mutex);
auto logger = spdlog::get(name);
if (logger) {
return logger;
}
if (m_console_loggers.find(name) != m_console_loggers.end())
return m_console_loggers[name];
if (m_file_loggers.find(name) != m_file_loggers.end())
return m_file_loggers[name];
spdlog::error("日志器 '{}' 不存在", name);
return nullptr;
}
}
void LoggerManager::setLevel(spdlog::level::level_enum level)
{
{
std::lock_guard<std::mutex> lock(m_mutex);
spdlog::set_level(level); // 设置全局日志级别
}
}
void LoggerManager::flushAll()
{
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_default_console_logger) {
m_default_console_logger->flush();
}
if (m_default_file_logger) {
m_default_file_logger->flush();
}
for (const auto& pair : m_console_loggers) {
if (pair.second) {
pair.second->flush();
}
}
for (const auto& pair : m_file_loggers) {
if (pair.second) {
pair.second->flush();
}
}
}
}
void LoggerManager::shutdownAll()
{
{
std::lock_guard<std::mutex> lock(m_mutex);
if (m_default_console_logger) {
m_default_console_logger->flush();
spdlog::drop(m_default_console_logger->name());
m_default_console_logger.reset();
}
if (m_default_file_logger) {
m_default_file_logger->flush();
spdlog::drop(m_default_file_logger->name());
m_default_file_logger.reset();
}
for (auto& pair : m_console_loggers) {
if (pair.second) {
pair.second->flush();
spdlog::drop(pair.second->name());
}
}
m_console_loggers.clear();
for (auto& pair : m_file_loggers) {
if (pair.second) {
pair.second->flush();
spdlog::drop(pair.second->name());
}
}
m_file_loggers.clear();
spdlog::shutdown(); // 关闭所有日志器
m_is_inited = false;
}
}
---
编译说明
要编译此代码,需要:
- 安装spdlog库(v1.x或更高版本)
- 链接必要的依赖项
使用建议
- 在应用程序启动时调用
init()方法初始化日志系统 - 根据需要创建不同类型的日志器
- 最好使用提供的宏来进行日志输出
- 在应用程序退出前调用
shutdown()确保所有日志被正确刷新
8417

被折叠的 条评论
为什么被折叠?



