手写一个线程安全的 C++ 日志库
在开发过程中,printf 或 std::cout 往往显得力不从心。它们缺乏结构化信息,难以区分日志级别,且在多线程环境下容易混行。为了解决这些问题,我们不妨自己造个轮子,实现一个支持多输出模式、线程安全且易于扩展的 C++ 日志库。
核心设计思路
一个完善的日志系统通常包含以下要素:
- 日志等级:DEBUG、INFO、WARNING、ERROR、FATAL,用于控制输出粒度。
- 输出目标:既能打印到屏幕方便调试,也能写入文件便于归档。
- 线程安全:多线程并发写入时不能出现数据竞争。
- 便捷调用:类似流式操作符,减少样板代码。
为了实现灵活的输出方式,我们采用策略模式。定义一个基类抽象出日志刷新接口,然后分别实现'屏幕输出'和'文件输出'的具体策略。这样后续如果需要增加数据库输出,只需新增一个策略类即可,无需修改主逻辑。
策略模式实现输出端
首先定义策略基类,声明纯虚函数用于刷新日志内容。
namespace log_lib {
class Strategy_Pattern {
public:
virtual ~Strategy_Pattern() = default;
// 纯虚函数,子类需实现具体刷新逻辑
virtual void Log_refresh_mode(const std::string &message) = 0;
};
}
屏幕输出策略
屏幕是公共资源,直接写入可能导致输出混乱,因此必须加锁保护。这里使用 pthread_mutex_t 来保证互斥。
#include <iostream>
#include <pthread.h>
namespace log_lib {
class Refresh_to_screen : public Strategy_Pattern {
public:
Refresh_to_screen() {
pthread_mutex_init(&_mutex, nullptr);
}
~Refresh_to_screen() {
pthread_mutex_destroy(&_mutex);
}
{
(&_mutex);
std::cout << message << std::endl;
(&_mutex);
}
:
_mutex;
};
}


