註冊表具有唯一標識,用於管理多個日誌 ```c++ // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. // Distributed under the MIT License (http://opensource.org ...
註冊表具有唯一標識,用於管理多個日誌
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
#pragma once
// Loggers registry of unique name->logger pointer
// An attempt to create a logger with an already existing name will result with spdlog_ex exception.
// If user requests a non existing logger, nullptr will be returned
// This class is thread safe
#include <spdlog/common.h>
#include <spdlog/details/periodic_worker.h>
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <mutex>
namespace spdlog {
class logger;
namespace details {
class thread_pool;
class SPDLOG_API registry
{
public:
using log_levels = std::unordered_map<std::string, level::level_enum>;
// 拷貝構造函數進行刪除(delete)的聲明。這意味著該類的拷貝構造函數被禁用,不允許進行拷貝構造。
registry(const registry &) = delete;
// 這意味著該類的賦值運算符重載被禁用,不允許進行對象之間的賦值操作。
registry &operator=(const registry &) = delete;
// 向全局的日誌器註冊表中註冊一個新的日誌器。
void register_logger(std::shared_ptr<logger> new_logger);
// 初始化一個新的日誌器並將其設置為【全局預設日誌器】。
void initialize_logger(std::shared_ptr<logger> new_logger);
// 通過名稱獲取logger
std::shared_ptr<logger> get(const std::string &logger_name);
// 獲取預設的全局日誌器。
std::shared_ptr<logger> default_logger();
// Return raw ptr to the default logger.
// To be used directly by the spdlog default api (e.g. spdlog::info)
// This make the default API faster, but cannot be used concurrently with set_default_logger().
// e.g do not call set_default_logger() from one thread while calling spdlog::info() from another.
// 獲取預設的全局日誌器的裸指針(raw pointer)。
// 裸指針是指向對象的普通指針,不包含智能指針的管理功能,需要手動管理對象的生命周期。
logger *get_default_raw();
// set default logger.
// default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map.
// 設置新的預設全局日誌器
void set_default_logger(std::shared_ptr<logger> new_default_logger);
// 設置日誌器的線程池。
// 通過設置日誌器的線程池,可以讓日誌器在後臺線程中執行寫入日誌的操作,從而減少主線程的阻塞時間,提高程式的性能和響應性。
// 如果日誌記錄是同步進行的(預設情況下),日誌消息的寫入操作會在主線程中直接完成,可能會對程式的性能產生影響。
// 而設置了線程池後,日誌消息的寫入操作將在後臺線程中進行,不會阻塞主線程的執行。
void set_tp(std::shared_ptr<thread_pool> tp);
// 獲取線程池
std::shared_ptr<thread_pool> get_tp();
// Set global formatter. Each sink in each logger will get a clone of this object
// 設置日誌器的日誌消息格式化器
// 日誌消息格式化器是用於將日誌消息的內容按照特定的格式進行格式化的組件
// 通過設置日誌器的格式化器,可以自定義日誌消息輸出的樣式,例如包含時間戳、日誌級別、日誌內容等信息,並將格式化後的日誌消息寫入到輸出目標(如控制台、文件等)。
void set_formatter(std::unique_ptr<formatter> formatter);
// 啟用日誌器的回溯(backtrace)功能。
void enable_backtrace(size_t n_messages);
// 關閉日誌器的回溯(backtrace)功能。
void disable_backtrace();
// 設置日誌的級別
void set_level(level::level_enum log_level);
// 日誌器的日誌刷新級別。
// 日誌刷新級別指定了日誌器在哪個日誌級別及以上時需要立即刷新日誌消息。
// 如果調用 flush_on(spdlog::level::err),它會設置日誌器在 err(錯誤)級別及以上時立即刷新日誌消息。
// 這意味著處於 err、critical 和 off 級別的日誌消息將在寫入後立即刷新,而低於這些級別的日誌消息(例如 info 或 debug)可能會被緩衝以提高效率。
void flush_on(level::level_enum log_level);
// 設置定時刷新日誌的時間間隔。
// 支持不同類型的時間間隔。Rep 和 Period 是時間間隔類型的模板參數,用於指定時間間隔的數值和時間單位。
// std::chrono::duration 是 C++ 標準庫中的時間間隔類模板,用於表示一段時間。
// std::lock_guard<std::mutex> lock(flusher_mutex_);這是一個互斥鎖 std::mutex 的鎖保護,用於保證在設置定時器時,其他線程不會同時進行刷新操作。
// 回調函數是 this->flush_all(),表示要執行日誌器的刷新操作。
template<typename Rep, typename Period>
void flush_every(std::chrono::duration<Rep, Period> interval)
{
std::lock_guard<std::mutex> lock(flusher_mutex_);
auto clbk = [this]() { this->flush_all(); };
// 這是一個定時器的成員變數,用於設置定時器,並將回調函數和時間間隔傳遞給 periodic_worker 構造函數。
// periodic_worker 是 spdlog 庫中的一個類,用於創建周期性定時器。
periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval);
}
// 設置錯誤處理函數(Error Handler)。
// 這是一個函數指針或函數對象參數,用於表示錯誤處理函數。錯誤處理函數是一個用戶定義的函數,用於處理在 spdlog 庫中可能發生的錯誤情況
// using err_handler = std::function<void(const std::string &err_msg)>;是一個函數對象類型,用於表示一個接受 const std::string & 類型參數的無返回值函數。
void set_error_handler(err_handler handler);
// 對所有已註冊的日誌器應用一個指定的函數。
// 對所有已創建的日誌器進行一些特定的操作,例如更改日誌器的配置、設置日誌級別等。
void apply_all(const std::function<void(const std::shared_ptr<logger>)> &fun);
// 將所有已註冊的日誌器的緩衝日誌消息刷新到輸出目標。
void flush_all();
// 從日誌器註冊表中移除指定名稱的日誌器。
void drop(const std::string &logger_name);
// 從日誌器註冊表中移除所有日誌器。
void drop_all();
// clean all resources and threads started by the registry
// 關閉所有已註冊的日誌器並釋放相關資源。
void shutdown();
// 獲取一個遞歸互斥鎖(recursive mutex)對象的引用。
// 遞歸互斥鎖是一種特殊類型的互斥鎖,允許同一線程多次對互斥鎖進行加鎖,而不會導致死鎖。
std::recursive_mutex &tp_mutex();
// 指定是否啟用自動註冊日誌器功能。
// 為true時,通過 spdlog::create 創建的日誌器將自動註冊到全局的日誌器註冊表中,方便後續的查找和使用。
// 為false時,通過 spdlog::create 創建的日誌器將不會自動註冊到日誌器註冊表中,需要手動調用其他函數(如 spdlog::register_logger)將其註冊
void set_automatic_registration(bool automatic_registration);
// set levels for all existing/future loggers. global_level can be null if should not set.
// 可以同時設置多個日誌器的日誌級別,並可以設置全局的日誌級別。這樣可以方便地統一管理多個日誌器的日誌級別,並靈活地控制日誌輸出的詳細程度。
// using log_levels = std::unordered_map<std::string, level::level_enum>;多個日誌級別配置,map類型
void set_levels(log_levels levels, level::level_enum *global_level);
// 獲取日誌器註冊表的單例實例。
// 日誌器註冊表是全局唯一的,為了方便使用,spdlog 使用了單例模式,即只允許存在一個註冊表實例。
static registry &instance();
// 根據環境變數設置日誌器的日誌級別。
// 使用環境變數來配置日誌級別具有靈活性,因為它允許在不修改代碼的情況下更改日誌級別。
// 通過在運行時設置環境變數,可以動態地調整日誌輸出的詳細程度,方便在不同的場景或部署環境下進行日誌記錄。
void apply_logger_env_levels(std::shared_ptr<logger> new_logger);
private:
registry();
~registry();
// 用於檢查是否存在指定名稱的日誌器,併在存在時拋出異常。
// 通過調用 throw_if_exists_ 函數,並傳遞一個日誌器的名稱作為參數,可以檢查註冊表中是否已經存在具有相同名稱的日誌器。
// 如果存在,該函數會拋出異常,提示名稱衝突,防止創建重名的日誌器。
void throw_if_exists_(const std::string &logger_name);
// 將指定的日誌器註冊到日誌器註冊表中。
void register_logger_(std::shared_ptr<logger> new_logger);
// 從配置中設置日誌器的日誌級別。
bool set_level_from_cfg_(logger *logger);
// 對日誌器註冊表進行線程同步的互斥鎖。對日誌器刷新操作進行線程同步的互斥鎖。
std::mutex logger_map_mutex_, flusher_mutex_;
// 遞歸互斥鎖對象的聲明。
std::recursive_mutex tp_mutex_;
// 日誌無序映射
std::unordered_map<std::string, std::shared_ptr<logger>> loggers_;
// 保存多個日誌器的名稱及對應的日誌級別。
log_levels log_levels_;
// formatter 是一個抽象基類,用於控制日誌消息的格式化方式
// 獨占指針
// 由於 std::unique_ptr 具有獨占性,即同一時刻只有一個 std::unique_ptr 可以擁有一個資源
// 因此 formatter_ 對象可以確保在其生命周期內,只有一個智能指針持有 formatter 對象。
// 這樣可以避免多個指針同時對同一個資源進行管理,確保資源的正確釋放。
std::unique_ptr<formatter> formatter_;
// 全局日誌級別變數的聲明和初始化。預設為info
spdlog::level::level_enum global_log_level_ = level::info;
// 日誌級別變數的聲明和初始化。flush_level_ 變數用於控制日誌的刷新行為。
level::level_enum flush_level_ = level::off;
// 錯誤處理器變數的聲明。
err_handler err_handler_;
// 線程池
std::shared_ptr<thread_pool> tp_;
// periodic_worker表示一個周期性任務的執行器。
// 在 spdlog 中,periodic_worker 類型可能表示一個周期性的定時任務執行器,用於定期執行某個操作。
std::unique_ptr<periodic_worker> periodic_flusher_;
// 預設日誌
std::shared_ptr<logger> default_logger_;
// 是否自動註冊,預設true
bool automatic_registration_ = true;
// 回溯級別預設為0
size_t backtrace_n_messages_ = 0;
};
} // namespace details
} // namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
# include "registry-inl.h"
#endif