【CSDN】:spdlog生成日志
【R】:Introduction to RcppSpdlog
【GitHub】:spdlog wiki
1、spdlog 静态库编译 |
1、spdlog 项目源码下载 github地址
2、cmake 编译配置工具下载 官网地址
3、cmake 构建工程【configer—>generate】
4、VS 打开 spdlog.sln,编译生成静态库【spdlogd.lib、spdlog.lib】
注意:1.5.0之前版本新建文件需手动,同时库和主程序都用到spdlog时,不会共享注册器信息,需各自操作
2、调用 spdlog 静态库 |
1、创建配置 Windows 控制台应用【支持C++11】
C/C++ — 常规 — 附加包含目录:设spdlog-1.x/include文件路径
链接器 — 常规 — 附加库目录:设spdlog 静态库文件路径
链接器 — 常规 — 附加依赖项:Debug模式添spdlogd.lib,Release模式添spdlog.lib
C/C++ — 预处理器 — 预处理器定义:设_SCL_SECURE_NO_WARNINGS
2、GitHub 样例源码
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
// spdlog usage example
#include
// 定义在spdlog等头文件前,否则覆盖, 调SPDLOG_TRACE等宏失效
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE
void load_levels_example();
void stdout_logger_example();
void basic_example();
void rotating_example();
void daily_example();
void async_example();
void binary_example();
void stopwatch_example();
void trace_example();
void multi_sink_example();
void user_defined_example();
void err_handler_example();
void syslog_example();
void custom_flags_example();
#include "spdlog/spdlog.h"
#include "spdlog/cfg/env.h" // support for loading levels from the environment variable
int main(int, char *[])
{
// Log levels can be loaded from argv/env using "SPDLOG_LEVEL"
load_levels_example();
spdlog::info("Welcome to spdlog version {}.{}.{} !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH);
spdlog::warn("Easy padding in numbers like {:08d}", 12); // 占位符, 共8位
spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); //进制:10、16、oct 8、2
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"); // 8字符空白位, 设居右or居左
// Runtime log levels
// 日志级别从低到高 trace, debug, info, warn, err, critical, off, n_levels
spdlog::set_level(spdlog::level::info); // Set global log level to info
spdlog::debug("This message should not be displayed!"); // 日志级别已调高, Debug级不输出
spdlog::set_level(spdlog::level::trace); // Set specific logger's log level
spdlog::debug("This message should be displayed.."); // 日志级别已调低, Debug级输出
// Customize msg format for all loggers
// https://github.com/gabime/spdlog/wiki/3.-Custom-formatting
spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [thread %t] %v"); // 变更输出格式
spdlog::info("This an info message with custom format");
spdlog::set_pattern("%+"); // back to default format // 返回默认格式
spdlog::set_level(spdlog::level::info);
// Backtrace support
// Loggers can store in a ring buffer all messages (including debug/trace) for later inspection.
// When needed, call dump_backtrace() to see what happened:
spdlog::enable_backtrace(10); // 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!
try
{
stdout_logger_example();
basic_example();
rotating_example();
daily_example();
async_example();
binary_example();
multi_sink_example();
user_defined_example();
err_handler_example();
trace_example();
stopwatch_example();
custom_flags_example();
// Flush all *registered* loggers using a worker thread every 3 seconds.
// note: registered loggers *must* be thread safe for this to work correctly!
spdlog::flush_every(std::chrono::seconds(3)); // 默认定时刷日志
// Apply some function on all registered loggers
spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) {
l->info("End of example."); });
// Release all spdlog resources, and drop all loggers in the registry.
// This is optional (only mandatory if using windows + async log).
spdlog::shutdown();
}
// Exceptions will only be thrown upon failed logger or sink construction (not during logging).
catch (const spdlog::spdlog_ex &ex)
{
std::printf("Log initialization failed: %s\n", ex.what());
return 1;
}
}
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_WARN
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/rotating_file_sink.h"
#include "spdlog/async.h"
namespace xxxx
{
enum class logger_type
{
file,
console
};
template<logger_type Type>
inline static void create_logging(const std::string& dir)
{
spdlog::init_thread_pool(8192 * 2, 1); // 16k
std::shared_ptr<spdlog::logger> l;
if (Type == logger_type::console)
{
l = spdlog::stdout_color_mt("some_unique_name");
}
else
{
l = spdlog::create_async_nb<spdlog::sinks::rotating_file_sink_mt>
("async_file_logger", dir, 1024 * 1024 * 10, 5);
}
// 日志级别从低到高 trace, debug, info, warn, err, critical, off, n_levels
l->flush_on(spdlog::level::warn);
l->set_pattern("[%Y-%m-%d %T.%e][tid:%t %s:%#] [%l] %v");
spdlog::flush_every(std::chrono::seconds(3));
spdlog::set_default_logger(l);
}
}
3、线程安全 |
非线程安全函数
set_error_handler(log_err_handler);
// returns a reference to a non thread safe vector,
// so don't modify it concurrently (e.g. logger->sinks().push_back(new_sink);)
logger::sinks()
创建 loggers
// To create thread safe loggers, use the _mt factory functions.
auto logger = spdlog::basic_logger_mt(...);
// To create single threaded loggers, use the _st factory functions.
auto logger = spdlog::basic_logger_st(...);
创建 sinks
// 线程安全的 sinks: sinks 以 _mt 结尾 (e.g daily_file_sink_mt)
//非线程安全的 sinks: sinks 以 _st 结尾 (e.g daily_file_sink_st)
4、创建 loggers |
通过工厂函数创建logger:spdlog wiki
#include "spdlog/sinks/stdout_color_sinks.h"
// or #include "spdlog/sinks/stdout_sinks.h" if no colors needed.
void stdout_logger_example()
{
// Create color multi threaded logger.
auto console = spdlog::stdout_color_mt("console");
// or for stderr:
// auto console = spdlog::stderr_color_mt("error-logger");
}
使用spdlog :: get 访问记录器【锚点:注册 loggers】
// Note: spdlog::get might slow your code down since it locks a mutex, so use with caution.
// It is advisable to save the shared_ptr returned and use it directly, at least in code hot paths.
class MyClass
{
private:
std::shared_ptr<spdlog::logger> _logger;
public:
MyClass()
{
//set _logger to some existing logger
_logger = spdlog::get("some_logger"); //存下指针,后续利用避免get
//or create directly
//_logger = spdlog::rotating_file_logger_mt("my_logger", ...);
}
};
创建基础 logger【不旋转】
#include "spdlog/sinks/basic_file_sink.h"
void basic_example()
{
// Create basic file logger (not rotated).
auto my_logger = spdlog::basic_logger_mt("file_logger", "logs/basic-log.txt");
}
创建滚动文件 logger【可设文件容量和滚动文件数】
#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",
1024 * 1024 * 5, 3);
}
创建每日文件 logger【可设固定时间点来新建文件】
#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);
}
工厂创建异步 logger【锚点:异步记录】
#include "spdlog/async.h"
void async_example()
{
// Default thread pool settings can be modified *before* creating the async logger:
// spdlog::init_thread_pool(32768, 1); // queue with max 32k items 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("async_file_logger", "logs/async_log.txt");
for (int i = 1; i < 101; ++i)
{
async_file->info("Async message #{}", i);
}
}
手动创建 loggers 【sink 和 logger 关系为 n:n】
auto sink = std::make_shared<spdlog::sinks::stdout_sink_mt>();
auto my_logger= std::make_shared<spdlog::logger>("mylogger", sink);
创建 loggers 挂载 多个sink
// A logger with multiple sinks (stdout and file) - each with a different format and log level.
void multi_sink_example()
{
// 日志级别从低到高 trace, debug, info, warn, err, critical, off, n_levels
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 with sinks init list
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");
}
auto shared_file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("fileName.txt");
auto first_logger = std::make_shared<spdlog::logger>("first_logger_name", shared_file_sink);
auto second_logger = std::make_unique<spdlog::logger>("second_logger_name", shared_file_sink);
5、自定义格式 |
自定义logger格式 spdlog wiki
// default logging format:[2014-10-31 23:46:59.678] [my_loggername] [info] Some message
// Set the pattern string (recommended)
set_pattern(pattern_string);
// Or implement custom formatter that implements the formatter interface and call
set_formatter(std::make_shared< my_custom_formatter >());
使用set_pattern(…)自定义格式
// Format can be applied globally to all registered loggers:
spdlog::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
// or to a specific logger object:
some_logger->set_pattern(">>>>>>>>> %H:%M:%S %z %v <<<<<<<<<");
// or to a specific sink object:
some_logger->sinks()[0]->set_pattern(">>>>>>>>> %H:%M:%S %z %v <<<<<<<<<");
some_logger->sinks()[1]->set_pattern("..");
自定义标志扩展 spdlog
// Log patterns can contain custom flags.
// this will add custom flag '%*' which will be bound to a instance
#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));
}
6、创建 Sinks |
sinks 是将日志实际写入其目标的对象,应仅负责单个目标【文件、控制台、数据库等】,且有各自的格式化程序对象专用实例。
每个logger都维护一组std :: shared_ptr < sink > , 在使用时将遍历该数组,逐个调sink(log_msg)
sink以_mt(多线程)或_st(单线程)为后缀,指示线程安全。
虽然不能同时从多线程中使用单线程sink,但是因无锁定,单线程sink更快。
rotating_file_sink【按文件大小和数量滚动文件】
// 滚动文件sink:当文件达设定内容大小时,则关闭并重命名,开新文件继续写; 当文件数达设定文件数,则删最旧文件并开新文件
#include "spdlog/sinks/rotating_file_sink.h"
...
// 设置滚动的最大文件大小 以及 最大文件数量, 例:文件大小最大为5MB,最多旋转3个文件
auto file_logger = spdlog::rotating_logger_mt("file_logger", "logs/mylogfile", 1048576 * 5, 3);
// 手动创建 sink 并传给 logger: 【方式二选一】
#include "spdlog/sinks/rotating_file_sink.h"
...
auto rotating = make_shared<spdlog::sinks::rotating_file_sink_mt> ("log_filename", 1024*1024, 5, false);
auto file_logger = make_shared<spdlog::logger>("my_logger", rotating);
daily_file_sink【每日定点新开文件】
// 每日文件sink: 每天在指定时间开新文件,并文件名后附一时间戳
#include "spdlog/sinks/daily_file_sink.h"
..
// 设置新开时间, 例:每天14:55
auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily", 14, 55);
simple_file_sink【简易写入文件】
// 简易文件sink: 无限制写入给定文件
#include "spdlog/sinks/basic_file_sink.h"
...
auto logger = spdlog::basic_logger_mt("mylogger", "log.txt");
stdout_sink/stderr_sink【标准 输出/错误输出】
#include "spdlog/sinks/stdout_sinks.h"
...
auto console = spdlog::stdout_logger_mt("console");
auto err_console = spdlog::stderr_logger_st("console");
stdout_sink/stderr_sink with colors【标准 输出/错误输出 附颜色】
#include "spdlog/sinks/stdout_color_sinks.h"
...
auto console = spdlog::stdout_color_mt("console");
auto err_console = spdlog::stderr_color_st("console");
// 或直接创建sink
auto sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
ostream_sink【字节流输出】
#include "spdlog/sinks/ostream_sink.h "
...
std::ostringstream oss;
auto ostream_sink = std::make_shared<spdlog::sinks::ostream_sink_mt> (oss);
auto logger = std::make_shared<spdlog::logger>("my_logger", ostream_sink);
null_sink【调试】
// 空sink: 丢弃日志, 可用作调试或用作参考实现
#include "spdlog/sinks/null_sink.h"
...
auto logger = spdlog::create<spdlog::sinks::null_sink_st>("null_logger");
syslog_sink【待定】
// POSIX syslog(3) sink: 将其日志发送到syslog
#include "spdlog/sinks/syslog_sink.h"
...
spdlog::syslog_logger logger("logger_name", "my_ident");
systemd_sink【待定】
// systemd sink:sink:将其日志发送到systemd
#include "spdlog/sinks/systemd_sink.h"
...
auto systemd_sink = std::make_shared<spdlog::sinks::systemd_sink_st>();
spdlog::logger logger("logger_name", systemd_sink);
dist_sink【分发消息给各接收器】
// 分发sink: 将日志消息分发到其他接收器列表
#include "spdlog/sinks/dist_sink.h"
...
auto dist_sink = make_shared<spdlog::sinks::dist_sink_st>();
auto sink1 = make_shared<spdlog::sinks::stdout_sink_st>();
auto sink2 = make_shared<spdlog::sinks::simple_file_sink_st>("mylog.log");
dist_sink->add_sink(sink1);
dist_sink->add_sink(sink2);
msvc_sink【用OutputDebugStringA输出调试信息】
// msvc sink: Windows调试接收器(使用OutputDebugStringA记录)
#include "spdlog/sinks/msvc_sink.h"
auto sink = std::make_shared<spdlog::sinks::msvc_sink_mt>();
auto logger = std::make_shared<spdlog::logger>("msvc_logger", sink);
dup_filter_sink【重复信息删除】
// 若前一个相同并且小于 max_skip_duration, 则跳过该消息。
#include "spdlog/sinks/dup_filter_sink.h"
auto dup_filter = std::make_shared<dup_filter_sink_st>(std::chrono::seconds(5));
dup_filter->add_sink(std::make_shared<stdout_color_sink_mt>());
spdlog::logger l("logger", dup_filter);
l.info("Hello");
l.info("Hello");
l.info("Hello");
l.info("Different Hello");
// 输出结果:
[2019-06-25 17:50:56.511] [logger] [info] Hello
[2019-06-25 17:50:56.512] [logger] [info] Skipped 3 duplicate messages..
[2019-06-25 17:50:56.512] [logger] [info] Different Hello
实现自己的 sink
#include "spdlog/sinks/base_sink.h"
// 继承base_sink【已处理锁锁定】,仅需实现sink_it_ 和 flush_
template<typename Mutex>
class my_sink : public spdlog::sinks::base_sink <Mutex>
{
...
protected:
void sink_it_(const spdlog::details::log_msg& msg) override
{
// log_msg is a struct containing the log entry info like level, timestamp, thread id etc.
// msg.raw contains pre formatted log
// If needed (very likely but not mandatory),
// the sink formats the message before sending it to its final destination:
spdlog::memory_buf_t formatted;
base_sink<Mutex>::formatter_->format(msg, formatted); // 最好先格式化信息
std::cout << fmt::to_string(formatted);
}
void flush_() override
{
std::cout << std::flush;
}
};
#include "spdlog/details/null_mutex.h"
#include
using my_sink_mt = my_sink<std::mutex>;
using my_sink_st = my_sink<spdlog::details::null_mutex>;
可将自定义sinks推入logger的skins vector,但无锁保护,非线程安全
inline std::vector<spdlog::sink_ptr> &spdlog::logger::sinks()
{
return sinks_;
}
7、注册 loggers |
根据 logger name 获取全局 logger
spdlog::get("logger1")->info("hello");
..
..
some other source file..
..
auto l = spdlog::get("logger1"); // 查找失败返回空
l->info("hello again");
注册/删除 手动创建的logger【锚点:创建 loggers】
// 通常无需注册logger,因为它们可自动注册, 若要注册手动创建的logger,则调register_logger(...)
// 注册表中若存在的相同名称时, 注册将引发spdlog :: spdlog_ex异常
spdlog::register_logger(some_logger)
// 从注册表中删除 指定名字的logger
// 若不存在指向该logger的其他shared_ptr,则该logger将关闭并释放资源
pdlog::drop("logger_name");
// 从注册表中删除 所有logger
spdlog::drop_all()
8、异步记录 |
使用< spdlog :: async_factory >模板参数 【锚点:创建 loggers】
#include "spdlog/async.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");
}
使用 spdlog::create_async< Sink > 创建 loggers【在队列上不会阻塞】
auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>(
"async_file_logger", "logs/async_log.txt");
使用 spdlog::create_async_nb< Sink > 创建 loggers
auto async_file = spdlog::create_async_nb<spdlog::sinks::basic_file_sink_mt>(
"async_file_logger", "logs/async_log.txt");
直接构造并使用全局线程池
spdlog::init_thread_pool(queue_size, n_threads);
auto logger = std::make_shared<spdlog::async_logger>(
"as", some_sink, spdlog::thread_pool(), async_overflow_policy::block);
直接构造并使用自定义线程池
// tp生命周期必须超过logger,因为logger获取了tp的weak_ptr
auto tp = std::make_shared<details::thread_pool>(queue_size, n_threads);
auto logger = std::make_shared<spdlog::async_logger>("as", some_sink, tp, async_overflow_policy::block);
满队列策略 选择设置
// 1、阻塞直至有更多空间(默认行为)
// 2、将队列中最旧消息换为新消息,而不是等待更多空间
auto logger = spdlog::create_async_nb<spdlog::sinks::basic_file_sink_mt>(
"async_file_logger", "logs/async_log.txt");
// 或者直接:
auto logger = std::make_shared<async_logger>("as", test_sink,
spdlog::thread_pool(), spdlog::async_overflow_policy::overrun_oldest);
spdlog 线程池设置
// 默认情况下,spdlog创建一个 queue_size=8192,n_threads=1 的全局线程池,以服务所有异步logger
// init_thread_pool将删除旧全局tp以新建线程池, 意味着所有使用旧tp的logger都将停止, 因此建议在创任何异步logger前调用
spdlog::init_thread_pool(queue_size, n_threads); //可配队列大小和线程数
// 如果不同的logger必须具有单独队列,则可创建池的不同实例并传递给logger
auto tp = std::make_shared<details::thread_pool>(128, 1);
auto logger = std::make_shared<async_logger>(
"as", some_sink, tp, async_overflow_policy::overrun_oldest);
auto tp2 = std::make_shared<details::thread_pool>(1024, 4);
auto logger2 = std::make_shared<async_logger>(
"as2", some_sink, tp2, async_overflow_policy::block);
// 多线程可能会重新排序消息, 若要保持原顺序, 则线程池仅创建一个线程
// 若使用异步日志, main退出之前调用spdlog::shutdown()
9、刷新策略 |
缺省情况下,spdlog允许基础libc在合适时刷新,也选用以下选项:
手动刷新
// logger将依次在每个sink上调用flush
logger->flush()
// 当前, 无需在关闭前显式调logger->flush()或spdlog::shutdown(), 因其会在程序退出时自动销毁。
// 但是, 若要在“立即”退出函数(abort或exit)前手动刷新所有异步looger,则需此前调spdlog :: shutdown()
基于级别刷新
// 可设置触发自动刷新的最低日志级别, 例:每当记录错误或更严重的消息时刷新
my_logger->flush_on(spdlog::level::err);
基于间隔刷新
// spdlg支持设置刷新间隔, 其由单个工作线程定期在每个logger上调用flush实现, 例:定期为所有注册的logger隔5秒刷新
spdlog::flush_every(std::chrono::seconds(5));
10、特殊操作 |
环境变量初始化日志等级
int main(int, char* [])
{
// Log levels can be loaded from argv/env using "SPDLOG_LEVEL"
spdlog::set_level(spdlog::level::trace);
spdlog::level::level_enum pre_level = spdlog::get_level(); //trace
load_levels_example();
spdlog::level::level_enum last_level = spdlog::get_level(); //info
// ...
}
#include "spdlog/cfg/env.h"
void load_levels_example()
{
// Set the log level to "info" and mylogger to to "trace":
// SPDLOG_LEVEL=info,mylogger=trace && ./example
spdlog::cfg::load_env_levels(); // VS 属性—调试—环境 中设SPDLOG_LEVEL=info,mylogger=trace
// or from command line:
// ./example SPDLOG_LEVEL=info,mylogger=trace
// #include "spdlog/cfg/argv.h" // for loading levels from argv
// spdlog::cfg::load_argv_levels(args, argv);
}
长数据 二进制转十六进制
// Log binary data as hex.
// Many types of std::container types can be used.
// Iterator 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. // 不用将输出拆分成几行
// {:a} - show ASCII if :n is not set // 显示ASCII
#include "spdlog/fmt/bin_to_hex.h"
void binary_example()
{
std::vector<char> buf(80);
for (int i = 0; i < 80; i++)
{
buf.push_back(static_cast<char>(i & 0xff));
}
spdlog::info("Binary example: {}", spdlog::to_hex(buf));
spdlog::info("Another binary example:{:n}", spdlog::to_hex(std::begin(buf), std::begin(buf) + 10));
// more examples:
spdlog::info("uppercase: {:X}", spdlog::to_hex(buf)); // 大写
spdlog::info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf)); // 大写 且 不留空格
spdlog::info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf)); // 大写 且 不留空格 且 无位置信息
spdlog::info("hexdump style: {:a}", spdlog::to_hex(buf)); // 显示ASCII
spdlog::info("hexdump style, 20 chars per line {:a}", spdlog::to_hex(buf, 20)); // 显示ASCII, 20字符一行
}
调宏输出日志
// Compile time log levels.
// define SPDLOG_ACTIVE_LEVEL to required level (e.g. SPDLOG_LEVEL_TRACE)
// 定义在spdlog等头文件前,否则覆盖, 调SPDLOG_TRACE等宏失效
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE
void trace_example()
{
spdlog::set_level(spdlog::level::trace); // 确保日志等级等于trace
// trace from default logger
SPDLOG_TRACE("Some trace message.. {} ,{}", 1, 3.23);
// debug from default logger
SPDLOG_DEBUG("Some debug message.. {} ,{}", 1, 3.23);
// trace from logger object
auto logger = spdlog::get("file_logger"); // 应注意get前需先register_logger, 因内含锁, 故建议存下返回值以利用
SPDLOG_LOGGER_TRACE(logger, "another trace message");
}
查看运行时间
// stopwatch example
#include "spdlog/stopwatch.h"
#include
void stopwatch_example()
{
spdlog::stopwatch sw;
std::this_thread::sleep_for(std::chrono::milliseconds(123));
spdlog::info("Stopwatch: {} seconds", sw);
}
自定义类型来输出日志
// User defined types logging by implementing operator<<
#include "spdlog/fmt/ostr.h" // must be included
struct my_type
{
int i;
template<typename OStream>
friend OStream &operator<<(OStream &os, const my_type &c)
{
return os << "[my_type i=" << c.i << "]";
}
};
void user_defined_example()
{
spdlog::info("user defined type: {}", my_type{
14});
}
自定义错误处理程序【将在日志失败时触发】
// 自定义错误处理程序, 将在日志失败时触发
void err_handler_example()
{
// can be set globally or per logger(logger->set_error_handler(..))
spdlog::set_error_handler([](const std::string &msg) {
printf("*** Custom log error handler: %s ***\n", msg.c_str());
});
}
Linux 系统应用 spdlog
// syslog example (linux/osx/freebsd)
#ifndef _WIN32
#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.");
}
#endif
Android 系统应用 spdlog
// Android example.
#if defined(__ANDROID__)
#include "spdlog/sinks/android_sink.h"
void android_example()
{
std::string tag = "spdlog-android";
auto android_logger = spdlog::android_logger_mt("android", tag);
android_logger->critical("Use \"adb shell logcat\" to view this message.");
}
#endif