參考文檔:https://spdlog.docsforge.com/master/
創(chuàng)新互聯(lián)長期為上1000+客戶提供的網(wǎng)站建設服務,團隊從業(yè)經(jīng)驗10年,關注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務;打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為城陽企業(yè)提供專業(yè)的成都網(wǎng)站建設、成都網(wǎng)站制作,城陽網(wǎng)站改版等技術服務。擁有十余年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。
Very fast, header only, C++ logging library.
一個header-only的C++日志庫,十分高效且易用。
https://github.com/gabime/spdlog
使用時只需要將git項目內(nèi)的/include/spdlog文件夾整個放入項目的include目錄下即可
#include "spdlog/spdlog.h"
int main()
{
spdlog::info("Welcome to spdlog!");
spdlog::error("Some error message with arg: {}", 1);
spdlog::warn("Easy padding in numbers like {:08d}", 12);
spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
spdlog::info("Support for floats {:03.2f}", 1.);
spdlog::info("Positional args are {1} {0}..", "too", "supported");
spdlog::info("{:<30}", "left aligned");
spdlog::set_level(spdlog::level::debug); // Set global log level to debug
spdlog::debug("This message should be displayed..");
// change log pattern
spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v");
// Compile time log levels
// define SPDLOG_ACTIVE_LEVEL to desired level
SPDLOG_TRACE("Some trace message with param {}", 42);
SPDLOG_DEBUG("Some debug message");
}
邏輯關系:每個logger包含一個vector,該vector由一個或多個std::shared_ptr<sink>
組成,logger的每條日志都會調(diào)用sink對象,由sink對象按照formatter的格式輸出到sink指定的地方(有可能是控制臺、文件等),接下來我們從內(nèi)到外的講解spdlog的這三個核心組件
formatter也即格式化對象,用于控制日志的輸出格式,spdlog自帶了默認的formatter,一般情況下,我們無需任何修改,直接使用即可。注意,每個sink會有一個formatter
默認formatter的格式為:[日期時間] [logger名] [log級別] log內(nèi)容
[2022-10-13 17:00:55.795] [sidecar] [debug] found env KAFKA_PARTITION_VALUE : -1
[2022-10-13 17:00:55.795] [sidecar_config] [debug] kafka_config.kafka_brokers : localhost:9092
[2022-10-13 17:00:55.795] [sidecar_config] [debug] kafka_config.kafka_main_topic : workflow_queue
[2022-10-13 17:00:55.795] [sidecar_config] [debug] kafka_config.kafka_partition_value : -1
[2022-10-13 17:00:55.795] [sidecar] [info] SidecarConfig initialized
如果默認的formatter不符合需求,可以自定義formatter,具體方式如下
每個sink對應著一個輸出目標和輸出格式,它內(nèi)部包含一個formatter,輸出目標可以是控制臺、文件等地方。
所有的sink都在命名空間spdlog::sinks下,可以自行探索
spdlog中創(chuàng)建控制臺sink非常簡單,該方式創(chuàng)建的sink會輸出到命令行終端,且是彩色的(也可以選非彩色的,但是有彩色的應該都會選彩色的吧……)。后綴的_mt代表多線程,_st代表單線程
auto sink1 = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
文件sink的類型有很多,這里展示幾種經(jīng)典類型
auto sink1 = std::make_shared<spdlog::sinks::basic_file_sink_mt>(log_file_name);//最簡單的文件sink,只需要指定文件名
auto sink2 = std::make_shared<spdlog::sinks::daily_file_sink_mt>(log_file_name, path, 14, 22);//每天的14點22分在path下創(chuàng)建新的文件
auto sink3 = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(log_file_name, 1024 * 1024 * 10, 100, false);//輪轉文件,一個文件滿了會寫到下一個文件,第二個參數(shù)是單文件大小上限,第三個參數(shù)是文件數(shù)量最大值
ostream_sink
syslog_sink
......
也可以通過繼承base_sink創(chuàng)建子類來自定義sink,具體可以參考:
https://spdlog.docsforge.com/v1.x/4.sinks/#implementing-your-own-sink
創(chuàng)建好sink后建議設置flush方式,否則可能無法立刻在file中看到logger的內(nèi)容
以下為兩種重要的flush方式設置(直接設置全局)
spdlog::flush_every(std::chrono::seconds(1));
spdlog::flush_on(spdlog::level::debug);
日志對象,每個logger內(nèi)包含了一個vector用于存放sink,每個sink都是相互獨立
因此一個日志對象在輸出日志時可以同時輸出到控制臺和文件等位置
如果整個項目中只需要一個logger,spdlog提供了最為便捷的默認logger,注意,該logger在全局公用,輸出到控制臺、多線程、彩色
//Use the default logger (stdout, multi-threaded, colored)
spdlog::info("Hello, {}!", "World");
大部分情況下默認logger是不夠用的,因為我們可能需要做不同項目模塊各自的logger,可能需要logger輸出到文件進行持久化,所以創(chuàng)建logger是很重要的一件事。好在創(chuàng)建logger也是非常簡單的!
與創(chuàng)建sink類似,我們可以非常便捷的創(chuàng)建logger
由于大部分時候一個logger只會有一個sink,所以spdlog提供了創(chuàng)建logger的接口并封裝了創(chuàng)建sink的過程
auto console = spdlog::stdout_color_mt("some_unique_name");//一個輸出到控制臺的彩色多線程logger,可以指定名字
auto file_logger = spdlog::rotating_logger_mt("file_logger", "logs/mylogfile", * 5, 3);//一個輸出到指定文件的輪轉文件logger,后面的參數(shù)指定了文件的信息
有時候,單sink的logger不夠用,那么可以先創(chuàng)建sink的vector,然后使用sinks_vector創(chuàng)建logger
以下樣例中,首先創(chuàng)建了sink的vector,然后創(chuàng)建了兩個sink并放入vector,最后使用該vector創(chuàng)建了logger,其中,set_level的過程不是必須的,register_logger一般是必須的,否則只能在創(chuàng)建logger的地方使用該logger,關于register的問題可以往下看
std::vector<spdlog::sink_ptr> sinks;
auto sink1 = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
sink1->set_level(SidecarLoggers::getGlobalLevel());
sinks.push_back(sink1);
auto sink2 = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(log_file_name, 1024 * 1024 * 10, 100, false);
sink2->set_level(spdlog::level::debug);
sinks.push_back(sink2);
auto logger = std::make_shared<spdlog::logger>("logger_name", begin(sinks), end(sinks));
logger->set_level(spdlog::level::debug);
spdlog::register_logger(logger);
在一個地方創(chuàng)建了logger卻只能在該處使用肯定是不好用的,所以spdlog提供了一個全局注冊和獲取logger,我們只需要在某處先創(chuàng)建logger并注冊,那么后面在其他地方使用時直接獲取就可以了
注冊:spdlog::register_logger()
獲?。簊pdlog::get()
//上面的代碼中我們注冊了一個logger,名字是logger_name,接下來嘗試獲取
auto logger = SidecarLoggers::getLogger("logger_name");
獲取到一個logger之后,就可以愉快的使用它了,使用起來很簡單
logger->debug("this is a debug msg");
logger->warn("warn!!!!");
logger->info("hello world");
logger->error("燙燙燙燙");
logger的默認level是info,如果處于開發(fā)環(huán)境或者生產(chǎn)環(huán)境,會只需要debug級別以上或者warn級別以上的log
要設置logger的級別,很簡單:
logger->set_level(spdlog::level::debug);
spdlog::set_level(spdlog::level::warn);
sink1->set_level(spdlog::level::info);
注意:一個logger內(nèi)假如有多個sink,那么這些sink分別設置level是可以不同的,但是由于logger本身也有l(wèi)evel,所以真正使用時,logger的level如果高于某個sink,會覆蓋該sink的level,所以建議此時把logger的level手動設置為debug(默認為info)
以下代碼為本人對spdlog的簡單使用封裝,主要功能有:
#ifndef SIDECAR_LOGGER_H
#define SIDECAR_LOGGER_H
#include <stdlib.h>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/stdout_sinks.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/sinks/daily_file_sink.h"
#include <vector>
class SidecarLoggers
{
public:
static void init();
static spdlog::level::level_enum getGlobalLevel();
static std::vector<spdlog::sink_ptr> createSinks(const std::string &log_file_name);
static void createLogger(const std::string &logger_name);
static std::shared_ptr<spdlog::logger> getLogger(const std::string &logger_name);
private:
static spdlog::level::level_enum global_level;
};
#endif
#include "sidecar_logger.h"
spdlog::level::level_enum SidecarLoggers::global_level = spdlog::level::info;
spdlog::level::level_enum SidecarLoggers::getGlobalLevel()
{
return global_level;
}
std::vector<spdlog::sink_ptr> SidecarLoggers::createSinks(const std::string &log_file_name)
{
std::vector<spdlog::sink_ptr> sinks;
auto sink1 = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
sink1->set_level(SidecarLoggers::getGlobalLevel());
sinks.push_back(sink1);
auto sink2 = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(log_file_name, 1024 * 1024 * 10, 100, false);
sink2->set_level(spdlog::level::debug);
sinks.push_back(sink2);
return sinks;
}
void SidecarLoggers::createLogger(const std::string &logger_name)
{
std::string log_file_name = logger_name + "_log.txt";
auto sinks = SidecarLoggers::createSinks(log_file_name);
auto logger = std::make_shared<spdlog::logger>(logger_name, begin(sinks), end(sinks));
logger->set_level(spdlog::level::debug);
spdlog::register_logger(logger);
}
std::shared_ptr<spdlog::logger> SidecarLoggers::getLogger(const std::string &logger_name){
auto logger = spdlog::get(logger_name);
if(!logger){//looger指向為空
createLogger(logger_name);
logger = spdlog::get(logger_name);
}
return logger;
}
void SidecarLoggers::init()
{
auto level = spdlog::level::debug;
if (std::getenv("STAGE") != NULL)
{
std::string stage = std::getenv("STAGE");
if (stage == "dev")
level = spdlog::level::debug;
}
SidecarLoggers::global_level = level;
spdlog::flush_every(std::chrono::seconds(1));
spdlog::flush_on(spdlog::level::debug);
SidecarLoggers::createLogger("sidecar");
}
標題名稱:【C++】spdlog光速入門,C++logger最簡單最快的庫
網(wǎng)站鏈接:http://chinadenli.net/article46/dsoiehg.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供做網(wǎng)站、云服務器、外貿(mào)建站、網(wǎng)站導航、建站公司、軟件開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)