g3log是一个高性能C++日志库,其代码十分精简和可读性强,本文将从3个方面详细介绍g3log源代码学习。
一、g3log源代码整体架构
g3log的整体架构十分清晰,其中有3个核心组件,分别是Logger、LogWorker和Sink。Logger负责产生日志记录,LogWorker是一个异步的队列,负责将Logger产生的日志记录进行处理和缓存,最终交由Sink进行输出。
class Logger { public: Logger(const std::string& loggerId, SinkHandle worker, LogLevel minimumLevel) { ... } virtual ~Logger(); void log(const LogMessage& message) { ... } ... };
class LogWorker { public: ... LogWorker(std::string id, std::unique_ptr sink, const int& maxMessageSize, const int& workerCount); virtual ~LogWorker(); inline int getWorkerId() const noexcept { return worker_id_; } void stop(); void send(std::unique_ptr); bool try_send(std::unique_ptr); void sendImmediate(std::unique_ptr); template inline void send(T&& message, const LEVELS& level) { send(LogMessage(std::forward(message), getWorkerId(), level), true); } ... };
class Sink { public: virtual ~Sink() = default; virtual void sink(const LogMessage& message) = 0; };
Logger、LogWorker、Sink三个组件各司其职,代码规范且易于扩展。
二、日志级别的控制和处理
g3log中有INFO、DEBUG、WARNING、ERROR和FATAL 5个级别的日志等级,并且可以通过配置文件来设置日志等级。在代码中,对于每个日志级别都有对应的宏定义,并且都会在编译时进行一次条件判断,从而确保了日志输出的高效性。
#define INFO_IF(instance, condition) \ if (condition) { \ if (auto log_message = (instance).debug()) { \ log_message->write().startPrint().stream() #define DEBUG_IF(instance, condition) \ if (condition) { \ if (auto log_message = (instance).debug()) { \ log_message->write().startPrint().stream() #define WARNING_IF(instance, condition) \ if (condition) { \ if (auto log_message = (instance).warning()) { \ log_message->write().startPrint().stream() #define ERROR_IF(instance, condition) \ if (condition) { \ if (auto log_message = (instance).error()) { \ log_message->write().startPrint().stream() #define FATAL_IF(instance, condition) \ if (condition) { \ if (auto log_message = (instance).fatal()) { \ log_message->write().startPrint().stream()
代码中对于每个宏定义都做了一次条件判断,只有当日志等级高于设置等级时,才会执行相应的日志操作,从而提高了日志输出性能。
三、日志输出效率的提高
g3log的异步输出机制可以提高日志系统的效率,其采用多个LogWorker来处理日志记录的缓存和输出,而且每个LogWorker维护一个RingBuffer,多个LogWorker之间可以互相切换和传输RingBuffer,从而实现了多线程并发处理。
class RingBuffer { public: RingBuffer() { clear(); } void push_back(const T data) { auto slot = ++_tail & _mask; _buffer[slot] = data; } T pop_front() { auto slot = ++_head & _mask; return _buffer[slot]; } ... };
在实现RingBuffer时采用了循环队列的设计,这样一来从队列头和尾部的插入和删除操作的处理速度就会非常快。
四、总结
通过对g3log源代码的学习,我们可以发现g3log的设计非常简单高效,代码规范而且易于扩展和维护。同时,其采用了异步输出机制和多线程并发处理等机制,也提高了日志系统的效率。
原创文章,作者:EZMXK,如若转载,请注明出处:https://www.506064.com/n/375558.html