尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

超快速!C++ 日志库 spdlog 安装便捷、特性丰富,附使用示例与基准测试

超快速!C++ 日志库 spdlog 安装便捷、特性丰富,附使用示例与基准测试 安装仅头文件版本将 include 文件夹复制到你的构建目录然后使用 C11 编译器进行编译。编译版本推荐编译速度更快$ git clone https://github.com/gabime/spdlog.git $ cd spdlog mkdir build cd build $ cmake .. cmake --build .具体使用方法可参考示例 CMakeLists.txt。支持的平台Linux、FreeBSD、OpenBSD、Solaris、AIXWindowsmsvc 2013cygwinmacOSclang 3.5Android。包管理器安装方式Debiansudo apt install libspdlog-devHomebrewbrew install spdlogMacPortssudo port install spdlogFreeBSDpkg install spdlogFedoradnf install spdlogGentooemerge dev-libs/spdlogArch Linuxpacman -S spdlogopenSUSEsudo zypper in spdlog-develALT Linuxapt-get install libspdlog-develvcpkgvcpkg install spdlogconanconan install --requiresspdlog/[*]condaconda install -c conda-forge spdlogbuild2depends: spdlog ^1.8.2。特性速度极快具体性能可参考下方的基准测试。仅头文件或编译使用提供灵活的使用方式。丰富的格式化功能借助优秀的 fmt 库实现。异步模式可选提高日志记录效率。自定义格式化满足不同的日志输出需求。多线程/单线程日志记录器适应不同的应用场景。多种日志目标包括滚动日志文件、每日日志文件、控制台日志支持颜色、syslog、Windows 事件日志、Windows 调试器OutputDebugString(..)还可将日志记录到 Qt 控件有示例。易于扩展可自定义日志目标。日志过滤日志级别可在运行时和编译时修改支持从命令行参数或环境变量加载日志级别。回溯支持将调试消息存储在环形缓冲区中可按需显示。使用示例基本用法#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.23456); spdlog::info(Positional args are {1} {0}.., too, supported); spdlog::info({:30}, left aligned); spdlog::set_level(spdlog::level::debug); // 设置全局日志级别为 debug spdlog::debug(This message should be displayed..); // 更改日志格式 spdlog::set_pattern([%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v); // 编译时日志级别 // 注意这不会改变当前日志级别仅会根据 SPDLOG_ACTIVE_LEVEL 移除发布代码中的调用 SPDLOG_TRACE(Some trace message with param {}, 42); SPDLOG_DEBUG(Some debug message); }创建标准输出/标准错误日志记录器对象#include spdlog/spdlog.h #include spdlog/sinks/stdout_color_sinks.h void stdout_example() { // 创建一个彩色多线程日志记录器 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)); }基本文件日志记录器#include spdlog/sinks/basic_file_sink.h void basic_logfile_example() { try { auto 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; } }滚动文件日志记录器#include spdlog/sinks/rotating_file_sink.h void rotating_example() { // 创建一个最大为 5 MB 且保留 3 个滚动文件的日志记录器 auto max_size 1048576 * 5; auto max_files 3; auto logger spdlog::rotating_logger_mt(some_logger_name, logs/rotating.txt, max_size, max_files); }每日文件日志记录器#include spdlog/sinks/daily_file_sink.h void daily_example() { // 创建一个每日日志记录器每天凌晨 2:30 创建新文件 auto logger spdlog::daily_logger_mt(daily_logger, logs/daily.txt, 2, 30); }回溯支持// 调试消息可存储在环形缓冲区中而非立即记录 // 这在需要时如发生错误显示调试日志很有用 // 需要时调用 dump_backtrace() 将消息转储到日志中 spdlog::enable_backtrace(32); // 在缓冲区中存储最新的 32 条消息 // 或者 my_logger-enable_backtrace(32).. for(int i 0; i 100; i) { spdlog::debug(Backtrace message {}, i); // 此时尚未记录 } // 例如如果发生错误 spdlog::dump_backtrace(); // 现在记录显示最后 32 条消息 // 或者 my_logger-dump_backtrace(32)..定期刷新// 每 3 秒定期刷新所有已注册的日志记录器 // 注意仅在所有日志记录器都是线程安全的“_mt” 日志记录器时使用 spdlog::flush_every(std::chrono::seconds(3));秒表功能#include spdlog/stopwatch.h void stopwatch_example() { spdlog::stopwatch sw; spdlog::debug(Elapsed {}, sw); spdlog::debug(Elapsed {:.3}, sw); }以十六进制记录二进制数据#include spdlog/fmt/bin_to_hex.h void binary_example() { auto console spdlog::get(console); std::array 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)); // 更多示例 // 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)); }多目标日志记录器每个目标有不同的格式和日志级别void multi_sink_example() { auto console_sink std::make_shared(); console_sink-set_level(spdlog::level::warn); console_sink-set_pattern([multi_sink_example] [%^%l%$] %v); auto file_sink std::make_shared(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); }注册多个日志记录器并更改全局级别void set_level_example() { auto logger1 spdlog::basic_logger_mt(logger1, logs/logger1.txt); auto logger2 spdlog::basic_logger_mt(logger2, logs/logger2.txt); spdlog::set_default_logger(logger2); spdlog::default_logger()-set_level(spdlog::level::trace); // 将默认日志记录器logger2的级别设置为 trace spdlog::trace(trace message to the logger2 (specified as default)); spdlog::set_level(spdlog::level::off); // 将所有已注册日志记录器的级别设置为 off禁用 logger1.warn(warn message will not appear because the level set to off); logger2.warn(warn message will not appear because the level set to off); spdlog::warn(warn message will not appear because the level set to off); }用户定义的日志事件回调void callback_example() { auto callback_sink std::make_shared([](const spdlog::details::log_msg msg) { // 例如你可以通过发送电子邮件通知自己 }); callback_sink-set_level(spdlog::level::err); auto console_sink std::make_shared(); spdlog::logger logger(custom_callback_logger, {console_sink, callback_sink}); logger.info(some info log); logger.error(critical issue); // 会触发通知 }异步日志记录#include spdlog/async.h #include spdlog/sinks/basic_file_sink.h void async_example() { // 在创建异步日志记录器之前可以修改默认线程池设置 // spdlog::init_thread_pool(8192, 1); // 队列有 8k 个项和 1 个后台线程 auto async_file spdlog::basic_logger_mt(async_file_logger, logs/async_log.txt); // 或者 // auto async_file spdlog::create_async(async_file_logger, logs/async_log.txt); }多目标异步日志记录器#include spdlog/async.h #include spdlog/sinks/stdout_color_sinks.h #include spdlog/sinks/rotating_file_sink.h void multi_sink_example2() { spdlog::init_thread_pool(8192, 1); auto stdout_sink std::make_shared(); auto rotating_sink std::make_shared(mylog.txt, 1024*1024*10, 3); std::vector sinks {stdout_sink, rotating_sink}; auto logger std::make_shared(loggername, sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block); spdlog::register_logger(logger); }用户定义类型template struct fmt::formatter : fmt::formatter { auto format(my_type my, format_context ctx) const - decltype(ctx.out()) { return fmt::format_to(ctx.out(), [my_type i{}], my.i); } }; void user_defined_example() { spdlog::info(user defined type: {}, my_type(14)); }日志模式中的用户定义标志#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 clone() const override { return spdlog::details::make_unique(); } }; void custom_flags_example() { auto formatter std::make_unique(); formatter-add_flag(*).set_pattern([%n] [%*] [%^%l%$] %v); spdlog::set_formatter(std::move(formatter)); }自定义错误处理程序void err_handler_example() { // 可以全局设置也可以为每个日志记录器设置logger-set_error_handler(..) spdlog::set_error_handler([](const std::string msg) { spdlog::get(console)-error(*** LOGGER ERROR ***: {}, msg); }); spdlog::get(console)-info(some invalid message to trigger an error {}{}{}{}, 3); }syslog 日志记录#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.); }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.); }从环境变量或命令行参数加载日志级别#include spdlog/cfg/env.h int main (int argc, char *argv[]) { spdlog::cfg::load_env_levels(); // 或者指定环境变量名 // MYAPP_LEVELinfo,myloggertrace ./example // spdlog::cfg::load_env_levels(MYAPP_LEVEL); // 或者从命令行加载 // ./example SPDLOG_LEVELinfo,myloggertrace // #include spdlog/cfg/argv.h // spdlog::cfg::load_argv_levels(argc, argv); }使用示例$ export SPDLOG_LEVELinfo,myloggertrace $ ./example日志文件打开/关闭事件处理程序void file_events_example() { // 将 spdlog::file_event_handlers 传递给文件目标以获取日志文件打开/关闭通知 spdlog::file_event_handlers handlers; handlers.before_open [](spdlog::filename_t filename) { spdlog::info(Before opening {}, filename); }; handlers.after_open [](spdlog::filename_t filename, std::FILE *fstream) { fputs(After opening\n, fstream); }; handlers.before_close [](spdlog::filename_t filename, std::FILE *fstream) { fputs(Before closing\n, fstream); }; handlers.after_close [](spdlog::filename_t filename) { spdlog::info(After closing {}, filename); }; auto my_logger spdlog::basic_logger_st(some_logger, logs/events-sample.txt, true, handlers); }替换默认日志记录器void replace_default_logger_example() { auto new_logger spdlog::basic_logger_mt(new_default_logger, logs/new-default-log.txt, true); spdlog::set_default_logger(new_logger); spdlog::info(new logger log message); }以美观的颜色将日志记录到 Qt#include spdlog/spdlog.h #include spdlog/sinks/qt_sinks.h MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { setMinimumSize(640, 480); auto log_widget new QTextEdit(this); setCentralWidget(log_widget); int max_lines 500; // 保持文本控件最多 500 行必要时移除旧行 auto logger spdlog::qt_color_logger_mt(qt_logger, log_widget, max_lines); logger-info(Some info message); }映射诊断上下文MDC#include spdlog/mdc.h void mdc_example() { spdlog::mdc::put(key1, value1); spdlog::mdc::put(key2, value2); // 如果不使用默认格式使用 % 格式化器打印 MDC 数据 // spdlog::set_pattern([%H:%M:%S %z] [%^%L%$] [%] %v); }基准测试以下是在 64 位 Ubuntu 系统、Intel i7 - 4770 CPU 3.40GHz 上进行的一些基准测试结果同步模式[info] ************************************************************** [info] Single thread, 1,000,000 iterations [info] ************************************************************** [info] basic_st Elapsed: 0.17 secs 5,777,626/sec [info] rotating_st Elapsed: 0.18 secs 5,475,894/sec [info] daily_st Elapsed: 0.20 secs 5,062,659/sec [info] empty_logger Elapsed: 0.07 secs 14,127,300/sec [info] ************************************************************** [info] C-string (400 bytes). Single thread, 1,000,000 iterations [info] ************************************************************** [info] basic_st Elapsed: 0.41 secs 2,412,483/sec [info] rotating_st Elapsed: 0.72 secs 1,389,196/sec [info] daily_st Elapsed: 0.42 secs 2,393,298/sec [info] null_st Elapsed: 0.04 secs 27,446,957/sec [info] ************************************************************** [info] 10 threads, competing over the same logger object, 1,000,000 iterations [info] ************************************************************** [info] basic_mt Elapsed: 0.60 secs 1,659,613/sec [info] rotating_mt Elapsed: 0.62 secs 1,612,493/sec [info] daily_mt Elapsed: 0.61 secs 1,638,305/sec [info] null_mt Elapsed: 0.16 secs 6,272,758/sec异步模式[info] ------------------------------------------------- [info] Messages : 1,000,000 [info] Threads : 10 [info] Queue : 8,192 slots [info] Queue memory : 8,192 x 272 2,176 KB [info] ------------------------------------------------- [info] [info] ********************************* [info] Queue Overflow Policy: block [info] ********************************* [info] Elapsed: 1.70784 secs 585,535/sec [info] Elapsed: 1.69805 secs 588,910/sec [info] Elapsed: 1.7026 secs 587,337/sec [info] [info] ********************************* [info] Queue Overflow Policy: overrun [info] ********************************* [info] Elapsed: 0.372816 secs 2,682,285/sec [info] Elapsed: 0.379758 secs 2,633,255/sec [info] Elapsed: 0.373532 secs 2,677,147/sec文档详细文档可在 wiki 页面中查找。
返回列表