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-tw/n/375558.html