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
微信扫一扫
支付宝扫一扫