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/zh-hant/n/375558.html
微信掃一掃
支付寶掃一掃