Log:Spdlog初探(1)

Log:Spdlog初探

簡介

公司需要開新項目,提議更換日誌庫,交給我讓我調研一下spdlog庫的使用。

spdlog簡介

Github地址:Github地址
官網介紹:Very fast, header-only/compiled, C++ logging library。輕量,僅有頭文件/編譯,C++日誌庫。
注意:Spdlog包含了C++11特性,需使用支持C++11特性的編譯器。

安裝/使用

Header only version

只是用頭文件版本。
官網說明:Copy the source folder to your build tree and use a C++11 compiler.
複製源文件文件夾到的你編譯鏈中 和 使用一個C++11編譯器。
源文件地址:源文件地址
源文件目錄結構

編譯靜態庫

Linux版本

注意:本機需要安裝好git,cmake。這裏就不介紹安裝git,還有cmake了。

$ git clone https://github.com/gabime/spdlog.git
$ cd spdlog && mkdir build && cd build
$ cmake .. && make -j
$ make install

命令翻譯

1.克隆項目到當前目錄,工程文件夾爲 spdlog
2.進入 spdlog文件夾 && 創建build文件夾 && 進入build文件夾
3.執行cmkae .. 命令構建makefile工程 && make 編譯
4.安裝。此命令爲安裝到系統環境中,使用時就不需要配置引用頭文件目錄,庫目錄。\
如果不使用改命令,則需要在build 目錄下的 lib文件夾找到編譯好的庫,在 include文件夾 在 引用的頭

Windows版本

下載地址:spdlog工程下載地址
Windows下將下載好的 zip包或者 .tar.gz包解壓到本地。構建cmake工程
注意:本機需要安裝好cmake。cmake下載地址:cmake下載地址,下載版本:cmake-3.17.0-rc3-win64-x64.msi

解壓spdlog.zip/spdlog.tar.gz 到 本地
進入spdlog-1.x目錄,新建文件夾 build 文件夾,output 文件夾 //配置編譯文件夾,編譯輸出文件夾
打開cmake-gui,配置cmake工程屬性 (#後爲按鈕名稱)
配置 CMakeLists.txt 路徑,編譯路徑 #configure
配置 Visual Studio 編譯器,平臺版本。根據自己需要配置  #Finish
配置 其他屬性,主要是 輸出目錄(安裝目錄),樣例,測試按照默認配置 #configure
等待輸出 Generating install / Configuring done  #Generate
等待輸出 Generating done cmake工程配置完成
打開VS,打開工程,工程文件目錄爲build目錄 ,工程文件 spdlog.sln
選擇ALL_BUILD項目,右鍵生成。等待生成完成。
選擇INSTALL,右鍵生成。等待安裝完成。即可在 output目錄看到輸出目錄(include,lib)
設置 example 爲活動項目,查看官方樣例。調試查看

配置 CMakeLists.txt 路徑,編譯路徑
配置源文件路徑,編譯路徑
配置 Visual Studio 編譯器,平臺版本。
配置編譯器
配置 其他屬性
其他配置屬性
生成完成界面
配置完成界面
spdlog 工程目錄結構如下
spdlog項目結構

代碼說明

設置日誌輸出樣式

相關函數:
默認樣式:[2014-10-31 23:46:59.678] [my_loggername] [info] Some message
設置日誌輸出樣式有兩種方法

  1. Set the pattern string (recommended):
set_pattern(pattern_string);
  1. mplement custom formatter that implements the formatter interface and call
set_formatter(std::make_unique<my_custom_formatter>());

針對第一種方法:

//應用於全局所有註冊的日誌樣式設置
spdlog::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
//應用於日誌對象的樣式設置
some_logger->set_pattern(">>>>>>>>> %H:%M:%S %z %v <<<<<<<<<");
//特定的接收器對象
some_logger->sinks()[0]->set_pattern(">>>>>>>>> %H:%M:%S %z %v <<<<<<<<<");
some_logger->sinks()[1]->set_pattern("..");

樣式輸出參數列表

flag meaning example
%v The actual text to log “some user text”
%t Thread id “1232”
%P Process id “3456”
%n Logger’s name “some logger name”
%l The log level of the message “debug”, “info”, etc
%L Short log level of the message “D”, “I”, etc
%a Abbreviated weekday name “Thu”
%A Full weekday name “Thursday”
%b Abbreviated month name “Aug”
%B Full month name “August”
%c Date and time representation “Thu Aug 23 15:35:46 2014”
%C Year in 2 digits “14”
%Y Year in 4 digits “2014”
%D or %x Short MM/DD/YY date “08/23/14”
%m Month 01-12 “11”
%d Day of month 01-31 “29”
%H Hours in 24 format 00-23 “23”
%I Hours in 12 format 01-12 “11”
%M Minutes 00-59 “59”
%S Seconds 00-59 “58”
%e Millisecond part of the current second 000-999 “678”
%f Microsecond part of the current second 000000-999999 “056789”
%F Nanosecond part of the current second 000000000-999999999 “256789123”
%p AM/PM “AM”
%r 12 hour clock “02:55:02 pm”
%R 24-hour HH:MM time, equivalent to %H:%M “23:55”
%T or %X ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S “23:55:59”
%z ISO 8601 offset from UTC in timezone ([+/-]HH:MM) “+02:00”
%E Seconds since the epoch “1528834770”
%% The % sign “%”
%+ spdlog’s default format “[2014-10-31 23:46:59.678] [mylogger] [info] Some message”
%^ start color range (can be used only once) “[mylogger] [info(green)] Some message”
%$ end color range (for example %1%$ %v) (can be used only once) [+++] Some message
%@ Source file and line (use SPDLOG_TRACE(…), SPDLOG_INFO(…) etc.) my_file.cpp:123
%s Basename of the source file (use SPDLOG_TRACE(…), SPDLOG_INFO(…) etc.) my_file.cpp
%g Full path of the source file (use SPDLOG_TRACE(…), SPDLOG_INFO(…) etc.) /some/dir/my_file.cpp
%# Source line (use SPDLOG_TRACE(…), SPDLOG_INFO(…) etc.) 123
%! Source function (use SPDLOG_TRACE(…), SPDLOG_INFO(…) etc. see tweakme for pretty-print) my_func
%o Elapsed time in milliseconds since previous message 456
%i Elapsed time in microseconds since previous message 456
%u Elapsed time in nanoseconds since previous message 11456
%O Elapsed time in seconds since previous message 4

自定義樣式參數設置
spdlog允許自定義樣式參數設置。方法樣例如下:
摘自官方樣例,不做說明。

#include "spdlog/pattern_formatter.h"
class my_formatter_flag : public spdlog::custom_flag_formatter
{
public:
    void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override
    {
        std::string some_txt = "custom-flag";
        dest.append(some_txt.data(), some_txt.data() + some_txt.size());
    }

    std::unique_ptr<custom_flag_formatter> clone() const override
    {
        return spdlog::details::make_unique<my_formatter_flag>();
    }
};

void custom_flags_example()
{
    using spdlog::details::make_unique; // for pre c++14
    auto formatter = make_unique<spdlog::pattern_formatter>();
    formatter->add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v");
    spdlog::set_formatter(std::move(formatter));
}

基礎函數說明

1.設置日誌等級

//設置全局註冊日誌等級
spdlog::set_level(spdlog::level::info); // Set global log level to info
//其他用法與設置日誌樣式相同

日誌等級說明:

//宏定義
#define SPDLOG_LEVEL_TRACE 0
#define SPDLOG_LEVEL_DEBUG 1
#define SPDLOG_LEVEL_INFO 2
#define SPDLOG_LEVEL_WARN 3
#define SPDLOG_LEVEL_ERROR 4
#define SPDLOG_LEVEL_CRITICAL 5
#define SPDLOG_LEVEL_OFF 6
//枚舉定義
enum level_enum
{
    trace = SPDLOG_LEVEL_TRACE,
    debug = SPDLOG_LEVEL_DEBUG,
    info = SPDLOG_LEVEL_INFO,
    warn = SPDLOG_LEVEL_WARN,
    err = SPDLOG_LEVEL_ERROR,
    critical = SPDLOG_LEVEL_CRITICAL,
    off = SPDLOG_LEVEL_OFF,
    n_levels
};

2.日誌打印函數

//全局註冊函數使用方法,使用如下方法默認輸出終端/控制檯
//info(""); 類似於 printf(),默認參數設置已經完成,()內爲具體消息。
//{}. 花括號爲參數代表,可以定義爲任意支持標準輸出格式類型
    spdlog::info("Welcome to spdlog version {}.{}.{}  !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH);
    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.23456);
    spdlog::info("Positional args are {1} {0}..", "too", "supported");
    spdlog::info("{:>8} aligned, {:<8} aligned", "right", "left");
//其他方向,對象/節點 按照對應調用方法即可,

3.backtrace/dump使用

//函數代碼來源:官方樣例
//enable_backtrace(20); 打開 backtrace/dump 功能,參數爲 dump個數
    spdlog::enable_backtrace(20); // create ring buffer with capacity of 10  messages
    for (int i = 0; i < 100; i++)
    {
    	//注意爲設置輸出等級之下的日誌
    	//
        spdlog::debug("Backtrace message {}", i); // not logged..
    }
    // e.g. if some error happened:
    spdlog::dump_backtrace(); // log them now!

backtrace/dump 會開闢一個緩衝區,將其他的等級之下的日誌保存起來,在需要的時候彈出來。
4.標準輸出/控制檯打印
標準輸出 依賴於 頭文件 “spdlog/sinks/stdout_color_sinks.h” 或者 #include “spdlog/sinks/stdout_sinks.h” 區別是 是否支持對輸出顏色的設置。

#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
// or #include "spdlog/sinks/stdout_sinks.h" if no colors needed.
void stdout_example()
{
    // create color multi threaded logger
    auto console = spdlog::stdout_color_mt("console");    
    auto err_logger = spdlog::stderr_color_mt("stderr");    
    spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)");
}

5.基礎文件輸出 Basic file logger

#include "spdlog/sinks/basic_file_sink.h"
void basic_logfile_example()
{
    try 
    {
        auto my_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt");
    }
    catch (const spdlog::spdlog_ex &ex)
    {
        std::cout << "Log init failed: " << ex.what() << std::endl;
    }
}

6.Rotating file

#include "spdlog/sinks/rotating_file_sink.h"
void rotating_example()
{
    // Create a file rotating logger with 5mb size max and 3 rotated files
    auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3);
}

7.Dailt file
生成日期日誌,每天指定時間生成對應的日誌文件,也是服務系統中常用的日誌,方便定位錯誤,日常檢查

#include "spdlog/sinks/daily_file_sink.h"
void daily_example()
{
    // Create a daily logger - a new file is created every day on 2:30am
    auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30);
}

8.Log binary data in hex

// many types of std::container<char> types can be used.
// ranges are supported too.
// format flags:
// {:X} - print in uppercase.
// {:s} - don't separate each byte with space.
// {:p} - don't print the position on each line start.
// {:n} - don't split the output to lines.

#include "spdlog/fmt/bin_to_hex.h"

void binary_example()
{
    auto console = spdlog::get("console");
    std::array<char, 80> buf;
    console->info("Binary example: {}", spdlog::to_hex(buf));
    console->info("Another binary example:{:n}", spdlog::to_hex(std::begin(buf), std::begin(buf) + 10));
    // more examples:
    // logger->info("uppercase: {:X}", spdlog::to_hex(buf));
    // logger->info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf));
    // logger->info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf));
}

9.異步日誌

#include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h"
void async_example()
{
    // default thread pool settings can be modified *before* creating the async logger:
    // spdlog::init_thread_pool(8192, 1); // queue with 8k items and 1 backing thread.
    auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
    // alternatively:
    // auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");   
}

10.系統日誌

#include "spdlog/sinks/syslog_sink.h"
void syslog_example()
{
    std::string ident = "spdlog-example";
    auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID);
    syslog_logger->warn("This is warning that will end up in syslog.");
}

11.多個日誌(Logger with multi sinks - each with different format and log level)

// create logger with 2 targets with different log levels and formats.
// the console will show only warnings or errors, while the file will log all.
void multi_sink_example()
{
    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    console_sink->set_level(spdlog::level::warn);
    console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v");

    auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true);
    file_sink->set_level(spdlog::level::trace);

    spdlog::logger logger("multi_sink", {console_sink, file_sink});
    logger.set_level(spdlog::level::debug);
    logger.warn("this should appear in both console and file");
    logger.info("this message should not appear in the console, only in the file");
}

其他特性說明

spdlog還支持線程池,異步多線程寫日誌,線程安全日誌,非線程安全日誌。
Loggers
To create thread safe loggers, use the _mt factory functions.
線程安全日誌 後綴爲 _mt

auto logger = spdlog::basic_logger_mt(...);

To create single threaded loggers, use the _st factory functions.
非線程安全 _st

auto logger = spdlog::basic_logger_st(...);

根據項目需求來使用。

結尾

製作了簡單介紹,創建與使用,其他複雜的應用還需要在實際項目中使用。最後還是使用了 glog 日誌模塊。主要想使用 backstrac/dump功能,結果不是預計中,項目奔潰/出錯,在日誌最後打印錯誤堆棧信息。測試時還是使用系統信號測試使用。

簡單的代碼片段

主要功能是,根據系統錯誤信號,打印錯誤日誌,堆棧日誌。其實想法是,每一個類設置對應的信號,錯誤輸出,然後建立一個全局的錯誤處理。只停留於想法,沒有時間做具體的實現。

#include "spdlog/sinks/rotating_file_sink.h"

void rotaing_file()
{
	auto rotating_logger = spdlog::rotating_logger_mt("file_logger","logs/rotating_file.txt",1048576 * 5,3);
	rotating_logger->set_pattern("[%Y-%m-%d %H:%M:%S] [%l] %! %v");
	rotating_logger->enable_backtrace(20);
	rotating_logger->set_level(spdlog::level::trace);
	rotating_logger->debug("rotating-debug-try {} {} {}", 2019, 03, "01");
	rotating_logger->info("rotating-info-try {} {} {}", 2019, 03, "01");
	char * a;
	memcpy(a, 0, 0);
	//	rotating_logger->flush();
}

void error_handle(int s)
{
	if (s == SIGSEGV)
	{
		spdlog::dump_backtrace();
	}
}

void trace_example()
{
	SPDLOG_TRACE("Some trace message..{},{}",1,3.23);
	SPDLOG_DEBUG("Some trace message..{},{}",1,3.23);

	auto logger = spdlog::get("file_logger");
	SPDLOG_LOGGER_TRACE(logger, "another trace message");
}

  1. +++ ↩︎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章