Line data Source code
1 : /**
2 : * @file logger.hpp
3 : * @brief 线程安全的日志输出工具
4 : *
5 : * 提供简洁的流式日志接口,确保多线程环境下日志输出的完整性。
6 : */
7 :
8 : #pragma once
9 :
10 : #include <mutex>
11 : #include <sstream>
12 : #include <unistd.h>
13 :
14 : namespace fix40 {
15 :
16 : /**
17 : * @class Logger
18 : * @brief 线程安全的日志输出器(单例模式)
19 : *
20 : * 确保每条日志完整输出,不会被其他线程的输出打断。
21 : * 使用 POSIX write() 系统调用保证原子性写入。
22 : *
23 : * @par 使用示例
24 : * @code
25 : * LOG() << "Connection established, fd=" << fd;
26 : * LOG() << "Received message: " << msg;
27 : * @endcode
28 : *
29 : * @note 日志会自动在末尾添加换行符
30 : */
31 : class Logger {
32 : public:
33 : /**
34 : * @brief 获取 Logger 单例实例
35 : * @return Logger& 单例引用
36 : */
37 4056 : static Logger& instance() {
38 : static Logger logger;
39 4056 : return logger;
40 : }
41 :
42 : /**
43 : * @brief 启用或禁用日志输出
44 : * @param enabled true 启用,false 禁用
45 : */
46 : void setEnabled(bool enabled) {
47 : enabled_ = enabled;
48 : }
49 :
50 : /**
51 : * @brief 检查日志是否启用
52 : * @return bool 是否启用
53 : */
54 : bool isEnabled() const {
55 : return enabled_;
56 : }
57 :
58 : /**
59 : * @class LogStream
60 : * @brief 日志流对象,支持流式输出
61 : *
62 : * 该对象在析构时将缓冲区内容原子性地写入标准输出。
63 : * 通过 RAII 机制确保日志完整输出。
64 : */
65 : class LogStream {
66 : public:
67 : /**
68 : * @brief 构造日志流
69 : * @param mtx 用于保护输出的互斥锁引用
70 : * @param enabled 是否启用输出
71 : */
72 4056 : LogStream(std::mutex& mtx, bool enabled) : mtx_(mtx), enabled_(enabled) {}
73 :
74 : /**
75 : * @brief 析构时输出日志
76 : *
77 : * 自动添加换行符,并使用 write() 系统调用原子性写入。
78 : */
79 8112 : ~LogStream() {
80 4056 : if (!enabled_) return;
81 4056 : buffer_ << '\n';
82 4056 : std::string str = buffer_.str();
83 4056 : std::lock_guard<std::mutex> lock(mtx_);
84 : // 使用 write() 系统调用,单次调用是原子的
85 4056 : ::write(STDOUT_FILENO, str.c_str(), str.size());
86 4056 : }
87 :
88 : LogStream(const LogStream&) = delete;
89 : LogStream& operator=(const LogStream&) = delete;
90 :
91 : /**
92 : * @brief 移动构造函数
93 : * @param other 源对象
94 : */
95 : LogStream(LogStream&& other) noexcept
96 : : mtx_(other.mtx_), enabled_(other.enabled_), buffer_(std::move(other.buffer_)) {}
97 :
98 : /**
99 : * @brief 流式输出操作符
100 : * @tparam T 值类型(需支持 ostream 输出)
101 : * @param value 要输出的值
102 : * @return LogStream& 返回自身以支持链式调用
103 : */
104 : template<typename T>
105 11558 : LogStream& operator<<(const T& value) {
106 11558 : if (enabled_) {
107 11558 : buffer_ << value;
108 : }
109 11558 : return *this;
110 : }
111 :
112 : private:
113 : std::mutex& mtx_; ///< 互斥锁引用
114 : bool enabled_; ///< 是否启用输出
115 : std::ostringstream buffer_; ///< 日志缓冲区
116 : };
117 :
118 : /**
119 : * @brief 创建日志流对象
120 : * @return LogStream 日志流对象
121 : */
122 4056 : LogStream log() {
123 4056 : return LogStream(mutex_, enabled_);
124 : }
125 :
126 : private:
127 : Logger() = default;
128 : std::mutex mutex_; ///< 保护日志输出的互斥锁
129 : bool enabled_ = true; ///< 日志开关
130 : };
131 :
132 : /**
133 : * @def LOG()
134 : * @brief 日志输出宏
135 : *
136 : * 使用方式:LOG() << "message" << value;
137 : */
138 : #define LOG() fix40::Logger::instance().log()
139 :
140 : } // namespace fix40
|