文章目錄
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 工程目錄結構如下
代碼說明
設置日誌輸出樣式
相關函數:
默認樣式:[2014-10-31 23:46:59.678] [my_loggername] [info] Some message
設置日誌輸出樣式有兩種方法:
- Set the pattern string (recommended):
set_pattern(pattern_string);
- 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");
}
+++ ↩︎