spdlog实现多线程日志管理器

使用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;
	}
}
---

编译说明

要编译此代码,需要:

  1. 安装spdlog库(v1.x或更高版本)
  2. 链接必要的依赖项

使用建议

  1. 在应用程序启动时调用init()方法初始化日志系统
  2. 根据需要创建不同类型的日志器
  3. 最好使用提供的宏来进行日志输出
  4. 在应用程序退出前调用shutdown()确保所有日志被正确刷新
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值