[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-11474":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":9,"totalLinesOfCode":9,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":9,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":9,"rankLanguage":9,"license":9,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":22,"hasPages":22,"topics":24,"createdAt":9,"pushedAt":9,"updatedAt":29,"readmeContent":30,"aiSummary":31,"trendingCount":16,"starSnapshotCount":16,"syncStatus":32,"lastSyncTime":33,"discoverSource":34},11474,"spdlog","gabime\u002Fspdlog","gabime","Fast C++ logging library.",null,"https:\u002F\u002Fgithub.com\u002Fgabime\u002Fspdlog","C++",28885,5166,443,37,0,27,49,142,81,45,false,"main",[25,26,27,28,5],"header-only","cpp11","cpp","logging","2026-06-12 02:02:32","# spdlog\r\n\r\n \r\n[![ci](https:\u002F\u002Fgithub.com\u002Fgabime\u002Fspdlog\u002Factions\u002Fworkflows\u002Flinux.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fgabime\u002Fspdlog\u002Factions\u002Fworkflows\u002Flinux.yml)&nbsp;\r\n[![ci](https:\u002F\u002Fgithub.com\u002Fgabime\u002Fspdlog\u002Factions\u002Fworkflows\u002Fwindows.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fgabime\u002Fspdlog\u002Factions\u002Fworkflows\u002Fwindows.yml)&nbsp;\r\n[![ci](https:\u002F\u002Fgithub.com\u002Fgabime\u002Fspdlog\u002Factions\u002Fworkflows\u002Fmacos.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fgabime\u002Fspdlog\u002Factions\u002Fworkflows\u002Fmacos.yml)&nbsp;\r\n[![Build status](https:\u002F\u002Fci.appveyor.com\u002Fapi\u002Fprojects\u002Fstatus\u002Fd2jnxclg20vd0o50?svg=true&branch=v1.x)](https:\u002F\u002Fci.appveyor.com\u002Fproject\u002Fgabime\u002Fspdlog) [![Release](https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Frelease\u002Fgabime\u002Fspdlog.svg)](https:\u002F\u002Fgithub.com\u002Fgabime\u002Fspdlog\u002Freleases\u002Flatest)\r\n\r\nFast C++ logging library\r\n\r\n\r\n## Install\r\n#### Header-only version\r\nCopy the include [folder](include\u002Fspdlog) to your build tree and use a C++11 compiler.\r\n\r\n#### Compiled version (recommended - much faster compile times)\r\n```console\r\n$ git clone https:\u002F\u002Fgithub.com\u002Fgabime\u002Fspdlog.git\r\n$ cd spdlog && mkdir build && cd build\r\n$ cmake .. && cmake --build .\r\n```\r\nsee example [CMakeLists.txt](example\u002FCMakeLists.txt) on how to use.\r\n\r\n## Platforms\r\n* Linux, FreeBSD, OpenBSD, Solaris, AIX\r\n* Windows (msvc 2013+, cygwin)\r\n* macOS (clang 3.5+)\r\n* Android\r\n\r\n## Package managers:\r\n* Debian: `sudo apt install libspdlog-dev`\r\n* Homebrew: `brew install spdlog`\r\n* MacPorts: `sudo port install spdlog`\r\n* FreeBSD:  `pkg install spdlog`\r\n* Fedora: `dnf install spdlog`\r\n* Gentoo: `emerge dev-libs\u002Fspdlog`\r\n* Arch Linux: `pacman -S spdlog`\r\n* openSUSE: `sudo zypper in spdlog-devel`\r\n* ALT Linux: `apt-get install libspdlog-devel`\r\n* vcpkg: `vcpkg install spdlog`\r\n* conan: `conan install --requires=spdlog\u002F[*]`\r\n* conda: `conda install -c conda-forge spdlog`\r\n* build2: ```depends: spdlog ^1.8.2```\r\n\r\n\r\n## Features\r\n* Very fast (see [benchmarks](#benchmarks) below).\r\n* Headers only or compiled\r\n* Feature-rich formatting, using the excellent [fmt](https:\u002F\u002Fgithub.com\u002Ffmtlib\u002Ffmt) library.\r\n* Asynchronous mode (optional)\r\n* [Custom](https:\u002F\u002Fgithub.com\u002Fgabime\u002Fspdlog\u002Fwiki\u002FCustom-formatting) formatting.\r\n* Multi\u002FSingle threaded loggers.\r\n* Various log targets:\r\n  * Rotating log files.\r\n  * Daily log files.\r\n  * Console logging (colors supported).\r\n  * syslog.\r\n  * Windows event log.\r\n  * Windows debugger (```OutputDebugString(..)```).\r\n  * Log to Qt widgets ([example](#log-to-qt-with-nice-colors)).\r\n  * Easily [extendable](https:\u002F\u002Fgithub.com\u002Fgabime\u002Fspdlog\u002Fwiki\u002FSinks#implementing-your-own-sink) with custom log targets.\r\n* Log filtering - log levels can be modified at runtime as well as compile time.\r\n* Support for loading log levels from argv or environment var.\r\n* [Backtrace](#backtrace-support) support - store debug messages in a ring buffer and display them later on demand.\r\n\r\n## Usage samples\r\n\r\n#### Basic usage\r\n```c++\r\n#include \"spdlog\u002Fspdlog.h\"\r\n\r\nint main() \r\n{\r\n    spdlog::info(\"Welcome to spdlog!\");\r\n    spdlog::error(\"Some error message with arg: {}\", 1);\r\n    \r\n    spdlog::warn(\"Easy padding in numbers like {:08d}\", 12);\r\n    spdlog::critical(\"Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}\", 42);\r\n    spdlog::info(\"Support for floats {:03.2f}\", 1.23456);\r\n    spdlog::info(\"Positional args are {1} {0}..\", \"too\", \"supported\");\r\n    spdlog::info(\"{:\u003C30}\", \"left aligned\");\r\n    \r\n    spdlog::set_level(spdlog::level::debug); \u002F\u002F Set *global* log level to debug\r\n    spdlog::debug(\"This message should be displayed..\");    \r\n    \r\n    \u002F\u002F change log pattern\r\n    spdlog::set_pattern(\"[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v\");\r\n    \r\n    \u002F\u002F Compile time log levels\r\n    \u002F\u002F Note that this does not change the current log level, it will only\r\n    \u002F\u002F remove (depending on SPDLOG_ACTIVE_LEVEL) the call on the release code.\r\n    SPDLOG_TRACE(\"Some trace message with param {}\", 42);\r\n    SPDLOG_DEBUG(\"Some debug message\");\r\n}\r\n\r\n```\r\n---\r\n#### Create stdout\u002Fstderr logger object\r\n```c++\r\n#include \"spdlog\u002Fspdlog.h\"\r\n#include \"spdlog\u002Fsinks\u002Fstdout_color_sinks.h\"\r\nvoid stdout_example()\r\n{\r\n    \u002F\u002F create a color multi-threaded logger\r\n    auto console = spdlog::stdout_color_mt(\"console\");    \r\n    auto err_logger = spdlog::stderr_color_mt(\"stderr\");    \r\n    spdlog::get(\"console\")->info(\"loggers can be retrieved from a global registry using the spdlog::get(logger_name)\");\r\n}\r\n```\r\n\r\n---\r\n#### Basic file logger\r\n```c++\r\n#include \"spdlog\u002Fsinks\u002Fbasic_file_sink.h\"\r\nvoid basic_logfile_example()\r\n{\r\n    try \r\n    {\r\n        auto logger = spdlog::basic_logger_mt(\"basic_logger\", \"logs\u002Fbasic-log.txt\");\r\n    }\r\n    catch (const spdlog::spdlog_ex &ex)\r\n    {\r\n        std::cout \u003C\u003C \"Log init failed: \" \u003C\u003C ex.what() \u003C\u003C std::endl;\r\n    }\r\n}\r\n```\r\n---\r\n#### Rotating files\r\n```c++\r\n#include \"spdlog\u002Fsinks\u002Frotating_file_sink.h\"\r\nvoid rotating_example()\r\n{\r\n    \u002F\u002F Create a file rotating logger with 5 MB size max and 3 rotated files\r\n    auto max_size = 1048576 * 5;\r\n    auto max_files = 3;\r\n    auto logger = spdlog::rotating_logger_mt(\"some_logger_name\", \"logs\u002Frotating.txt\", max_size, max_files);\r\n}\r\n```\r\n\r\n---\r\n#### Daily files\r\n```c++\r\n\r\n#include \"spdlog\u002Fsinks\u002Fdaily_file_sink.h\"\r\nvoid daily_example()\r\n{\r\n    \u002F\u002F Create a daily logger - a new file is created every day at 2:30 am\r\n    auto logger = spdlog::daily_logger_mt(\"daily_logger\", \"logs\u002Fdaily.txt\", 2, 30);\r\n}\r\n\r\n```\r\n\r\n---\r\n#### Backtrace support\r\n```c++\r\n\u002F\u002F Debug messages can be stored in a ring buffer instead of being logged immediately.\r\n\u002F\u002F This is useful to display debug logs only when needed (e.g. when an error happens).\r\n\u002F\u002F When needed, call dump_backtrace() to dump them to your log.\r\n\r\nspdlog::enable_backtrace(32); \u002F\u002F Store the latest 32 messages in a buffer. \r\n\u002F\u002F or my_logger->enable_backtrace(32)..\r\nfor(int i = 0; i \u003C 100; i++)\r\n{\r\n  spdlog::debug(\"Backtrace message {}\", i); \u002F\u002F not logged yet..\r\n}\r\n\u002F\u002F e.g. if some error happened:\r\nspdlog::dump_backtrace(); \u002F\u002F log them now! show the last 32 messages\r\n\u002F\u002F or my_logger->dump_backtrace(32)..\r\n```\r\n\r\n---\r\n#### Periodic flush\r\n```c++\r\n\u002F\u002F periodically flush all *registered* loggers every 3 seconds:\r\n\u002F\u002F warning: only use if all your loggers are thread-safe (\"_mt\" loggers)\r\nspdlog::flush_every(std::chrono::seconds(3));\r\n\r\n```\r\n\r\n---\r\n#### Stopwatch\r\n```c++\r\n\u002F\u002F Stopwatch support for spdlog\r\n#include \"spdlog\u002Fstopwatch.h\"\r\nvoid stopwatch_example()\r\n{\r\n    spdlog::stopwatch sw;    \r\n    spdlog::debug(\"Elapsed {}\", sw);\r\n    spdlog::debug(\"Elapsed {:.3}\", sw);       \r\n}\r\n\r\n```\r\n\r\n---\r\n#### Log binary data in hex\r\n```c++\r\n\u002F\u002F many types of std::container\u003Cchar> types can be used.\r\n\u002F\u002F ranges are supported too.\r\n\u002F\u002F format flags:\r\n\u002F\u002F {:X} - print in uppercase.\r\n\u002F\u002F {:s} - don't separate each byte with space.\r\n\u002F\u002F {:p} - don't print the position on each line start.\r\n\u002F\u002F {:n} - don't split the output into lines.\r\n\u002F\u002F {:a} - show ASCII if :n is not set.\r\n\r\n#include \"spdlog\u002Ffmt\u002Fbin_to_hex.h\"\r\n\r\nvoid binary_example()\r\n{\r\n    auto console = spdlog::get(\"console\");\r\n    std::array\u003Cchar, 80> buf;\r\n    console->info(\"Binary example: {}\", spdlog::to_hex(buf));\r\n    console->info(\"Another binary example:{:n}\", spdlog::to_hex(std::begin(buf), std::begin(buf) + 10));\r\n    \u002F\u002F more examples:\r\n    \u002F\u002F logger->info(\"uppercase: {:X}\", spdlog::to_hex(buf));\r\n    \u002F\u002F logger->info(\"uppercase, no delimiters: {:Xs}\", spdlog::to_hex(buf));\r\n    \u002F\u002F logger->info(\"uppercase, no delimiters, no position info: {:Xsp}\", spdlog::to_hex(buf));\r\n}\r\n\r\n```\r\n\r\n---\r\n#### Logger with multi sinks - each with a different format and log level\r\n```c++\r\n\r\n\u002F\u002F create a logger with 2 targets, with different log levels and formats.\r\n\u002F\u002F The console will show only warnings or errors, while the file will log all. \r\nvoid multi_sink_example()\r\n{\r\n    auto console_sink = std::make_shared\u003Cspdlog::sinks::stdout_color_sink_mt>();\r\n    console_sink->set_level(spdlog::level::warn);\r\n    console_sink->set_pattern(\"[multi_sink_example] [%^%l%$] %v\");\r\n\r\n    auto file_sink = std::make_shared\u003Cspdlog::sinks::basic_file_sink_mt>(\"logs\u002Fmultisink.txt\", true);\r\n    file_sink->set_level(spdlog::level::trace);\r\n\r\n    spdlog::logger logger(\"multi_sink\", {console_sink, file_sink});\r\n    logger.set_level(spdlog::level::debug);\r\n    logger.warn(\"this should appear in both console and file\");\r\n    logger.info(\"this message should not appear in the console, only in the file\");\r\n}\r\n```\r\n\r\n---\r\n#### Register several loggers - change global level\r\n```c++\r\n\r\n\u002F\u002F Creation of loggers. Set levels to all registered loggers. \r\nvoid set_level_example()\r\n{\r\n    auto logger1 = spdlog::basic_logger_mt(\"logger1\", \"logs\u002Flogger1.txt\");\r\n    auto logger2 = spdlog::basic_logger_mt(\"logger2\", \"logs\u002Flogger2.txt\");\r\n\r\n    spdlog::set_default_logger(logger2);\r\n    spdlog::default_logger()->set_level(spdlog::level::trace); \u002F\u002F set level for the default logger (logger2) to trace\r\n\r\n    spdlog::trace(\"trace message to the logger2 (specified as default)\");\r\n\r\n    spdlog::set_level(spdlog::level::off) \u002F\u002F (sic!) set level for *all* registered loggers to off (disable)\r\n  \r\n    logger1.warn(\"warn message will not appear because the level set to off\");\r\n    logger2.warn(\"warn message will not appear because the level set to off\");\r\n    spdlog::warn(\"warn message will not appear because the level set to off\");\r\n}\r\n```\r\n\r\n---\r\n#### User-defined callbacks about log events\r\n```c++\r\n\r\n\u002F\u002F create a logger with a lambda function callback, the callback will be called\r\n\u002F\u002F each time something is logged to the logger\r\nvoid callback_example()\r\n{\r\n    auto callback_sink = std::make_shared\u003Cspdlog::sinks::callback_sink_mt>([](const spdlog::details::log_msg &msg) {\r\n         \u002F\u002F for example you can be notified by sending an email to yourself\r\n    });\r\n    callback_sink->set_level(spdlog::level::err);\r\n\r\n    auto console_sink = std::make_shared\u003Cspdlog::sinks::stdout_color_sink_mt>();\r\n    spdlog::logger logger(\"custom_callback_logger\", {console_sink, callback_sink});\r\n\r\n    logger.info(\"some info log\");\r\n    logger.error(\"critical issue\"); \u002F\u002F will notify you\r\n}\r\n```\r\n\r\n---\r\n#### Asynchronous logging\r\n```c++\r\n#include \"spdlog\u002Fasync.h\"\r\n#include \"spdlog\u002Fsinks\u002Fbasic_file_sink.h\"\r\nvoid async_example()\r\n{\r\n    \u002F\u002F default thread pool settings can be modified *before* creating the async logger:\r\n    \u002F\u002F spdlog::init_thread_pool(8192, 1); \u002F\u002F queue with 8k items and 1 backing thread.\r\n    auto async_file = spdlog::basic_logger_mt\u003Cspdlog::async_factory>(\"async_file_logger\", \"logs\u002Fasync_log.txt\");\r\n    \u002F\u002F alternatively:\r\n    \u002F\u002F auto async_file = spdlog::create_async\u003Cspdlog::sinks::basic_file_sink_mt>(\"async_file_logger\", \"logs\u002Fasync_log.txt\");   \r\n}\r\n\r\n```\r\n\r\n---\r\n#### Asynchronous logger with multi sinks\r\n```c++\r\n#include \"spdlog\u002Fasync.h\"\r\n#include \"spdlog\u002Fsinks\u002Fstdout_color_sinks.h\"\r\n#include \"spdlog\u002Fsinks\u002Frotating_file_sink.h\"\r\n\r\nvoid multi_sink_example2()\r\n{\r\n    spdlog::init_thread_pool(8192, 1);\r\n    auto stdout_sink = std::make_shared\u003Cspdlog::sinks::stdout_color_sink_mt >();\r\n    auto rotating_sink = std::make_shared\u003Cspdlog::sinks::rotating_file_sink_mt>(\"mylog.txt\", 1024*1024*10, 3);\r\n    std::vector\u003Cspdlog::sink_ptr> sinks {stdout_sink, rotating_sink};\r\n    auto logger = std::make_shared\u003Cspdlog::async_logger>(\"loggername\", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block);\r\n    spdlog::register_logger(logger);\r\n}\r\n```\r\n \r\n---\r\n#### User-defined types\r\n```c++\r\ntemplate\u003C>\r\nstruct fmt::formatter\u003Cmy_type> : fmt::formatter\u003Cstd::string>\r\n{\r\n    auto format(my_type my, format_context &ctx) const -> decltype(ctx.out())\r\n    {\r\n        return fmt::format_to(ctx.out(), \"[my_type i={}]\", my.i);\r\n    }\r\n};\r\n\r\nvoid user_defined_example()\r\n{\r\n    spdlog::info(\"user defined type: {}\", my_type(14));\r\n}\r\n\r\n```\r\n\r\n---\r\n#### User-defined flags in the log pattern\r\n```c++ \r\n\u002F\u002F Log patterns can contain custom flags.\r\n\u002F\u002F the following example will add new flag '%*' - which will be bound to a \u003Cmy_formatter_flag> instance.\r\n#include \"spdlog\u002Fpattern_formatter.h\"\r\nclass my_formatter_flag : public spdlog::custom_flag_formatter\r\n{\r\npublic:\r\n    void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override\r\n    {\r\n        std::string some_txt = \"custom-flag\";\r\n        dest.append(some_txt.data(), some_txt.data() + some_txt.size());\r\n    }\r\n\r\n    std::unique_ptr\u003Ccustom_flag_formatter> clone() const override\r\n    {\r\n        return spdlog::details::make_unique\u003Cmy_formatter_flag>();\r\n    }\r\n};\r\n\r\nvoid custom_flags_example()\r\n{    \r\n    auto formatter = std::make_unique\u003Cspdlog::pattern_formatter>();\r\n    formatter->add_flag\u003Cmy_formatter_flag>('*').set_pattern(\"[%n] [%*] [%^%l%$] %v\");\r\n    spdlog::set_formatter(std::move(formatter));\r\n}\r\n\r\n```\r\n\r\n---\r\n#### Custom error handler\r\n```c++\r\nvoid err_handler_example()\r\n{\r\n    \u002F\u002F can be set globally or per logger(logger->set_error_handler(..))\r\n    spdlog::set_error_handler([](const std::string &msg) { spdlog::get(\"console\")->error(\"*** LOGGER ERROR ***: {}\", msg); });\r\n    spdlog::get(\"console\")->info(\"some invalid message to trigger an error {}{}{}{}\", 3);\r\n}\r\n\r\n```\r\n\r\n---\r\n#### syslog\r\n```c++\r\n#include \"spdlog\u002Fsinks\u002Fsyslog_sink.h\"\r\nvoid syslog_example()\r\n{\r\n    std::string ident = \"spdlog-example\";\r\n    auto syslog_logger = spdlog::syslog_logger_mt(\"syslog\", ident, LOG_PID);\r\n    syslog_logger->warn(\"This is warning that will end up in syslog.\");\r\n}\r\n```\r\n---\r\n#### Android example\r\n```c++\r\n#include \"spdlog\u002Fsinks\u002Fandroid_sink.h\"\r\nvoid android_example()\r\n{\r\n    std::string tag = \"spdlog-android\";\r\n    auto android_logger = spdlog::android_logger_mt(\"android\", tag);\r\n    android_logger->critical(\"Use \\\"adb shell logcat\\\" to view this message.\");\r\n}\r\n```\r\n\r\n---\r\n#### Load log levels from the env variable or argv\r\n\r\n```c++\r\n#include \"spdlog\u002Fcfg\u002Fenv.h\"\r\nint main (int argc, char *argv[])\r\n{\r\n    spdlog::cfg::load_env_levels();\r\n    \u002F\u002F or specify the env variable name:\r\n    \u002F\u002F MYAPP_LEVEL=info,mylogger=trace && .\u002Fexample\r\n    \u002F\u002F spdlog::cfg::load_env_levels(\"MYAPP_LEVEL\");\r\n    \u002F\u002F or from the command line:\r\n    \u002F\u002F .\u002Fexample SPDLOG_LEVEL=info,mylogger=trace\r\n    \u002F\u002F #include \"spdlog\u002Fcfg\u002Fargv.h\" \u002F\u002F for loading levels from argv\r\n    \u002F\u002F spdlog::cfg::load_argv_levels(argc, argv);\r\n}\r\n```\r\nSo then you can:\r\n\r\n```console\r\n$ export SPDLOG_LEVEL=info,mylogger=trace\r\n$ .\u002Fexample\r\n```\r\n\r\n\r\n---\r\n#### Log file open\u002Fclose event handlers\r\n```c++\r\n\u002F\u002F You can get callbacks from spdlog before\u002Fafter a log file has been opened or closed. \r\n\u002F\u002F This is useful for cleanup procedures or for adding something to the start\u002Fend of the log file.\r\nvoid file_events_example()\r\n{\r\n    \u002F\u002F pass the spdlog::file_event_handlers to file sinks for open\u002Fclose log file notifications\r\n    spdlog::file_event_handlers handlers;\r\n    handlers.before_open = [](spdlog::filename_t filename) { spdlog::info(\"Before opening {}\", filename); };\r\n    handlers.after_open = [](spdlog::filename_t filename, std::FILE *fstream) { fputs(\"After opening\\n\", fstream); };\r\n    handlers.before_close = [](spdlog::filename_t filename, std::FILE *fstream) { fputs(\"Before closing\\n\", fstream); };\r\n    handlers.after_close = [](spdlog::filename_t filename) { spdlog::info(\"After closing {}\", filename); };\r\n    auto my_logger = spdlog::basic_logger_st(\"some_logger\", \"logs\u002Fevents-sample.txt\", true, handlers);        \r\n}\r\n```\r\n\r\n---\r\n#### Replace the Default Logger\r\n```c++\r\nvoid replace_default_logger_example()\r\n{\r\n    auto new_logger = spdlog::basic_logger_mt(\"new_default_logger\", \"logs\u002Fnew-default-log.txt\", true);\r\n    spdlog::set_default_logger(new_logger);\r\n    spdlog::info(\"new logger log message\");\r\n}\r\n```\r\n\r\n---\r\n#### Log to Qt with nice colors\r\n```c++\r\n#include \"spdlog\u002Fspdlog.h\"\r\n#include \"spdlog\u002Fsinks\u002Fqt_sinks.h\"\r\nMainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)\r\n{\r\n    setMinimumSize(640, 480);\r\n    auto log_widget = new QTextEdit(this);\r\n    setCentralWidget(log_widget);\r\n    int max_lines = 500; \u002F\u002F keep the text widget to max 500 lines. remove old lines if needed.\r\n    auto logger = spdlog::qt_color_logger_mt(\"qt_logger\", log_widget, max_lines);\r\n    logger->info(\"Some info message\");\r\n}\r\n```\r\n---\r\n\r\n#### Mapped Diagnostic Context\r\n```c++\r\n\u002F\u002F Mapped Diagnostic Context (MDC) is a map that stores key-value pairs (string values) in thread local storage.\r\n\u002F\u002F Each thread maintains its own MDC, which loggers use to append diagnostic information to log outputs.\r\n\u002F\u002F Note: it is not supported in asynchronous mode due to its reliance on thread-local storage.\r\n#include \"spdlog\u002Fmdc.h\"\r\nvoid mdc_example()\r\n{\r\n    spdlog::mdc::put(\"key1\", \"value1\");\r\n    spdlog::mdc::put(\"key2\", \"value2\");\r\n    \u002F\u002F if not using the default format, use the %& formatter to print mdc data\r\n    \u002F\u002F spdlog::set_pattern(\"[%H:%M:%S %z] [%^%L%$] [%&] %v\");\r\n}\r\n```\r\n---\r\n## Benchmarks\r\n\r\nBelow are some [benchmarks](bench\u002Fbench.cpp) done in Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz\r\n\r\n#### Synchronous mode\r\n```\r\n[info] **************************************************************\r\n[info] Single thread, 1,000,000 iterations\r\n[info] **************************************************************\r\n[info] basic_st         Elapsed: 0.17 secs        5,777,626\u002Fsec\r\n[info] rotating_st      Elapsed: 0.18 secs        5,475,894\u002Fsec\r\n[info] daily_st         Elapsed: 0.20 secs        5,062,659\u002Fsec\r\n[info] empty_logger     Elapsed: 0.07 secs       14,127,300\u002Fsec\r\n[info] **************************************************************\r\n[info] C-string (400 bytes). Single thread, 1,000,000 iterations\r\n[info] **************************************************************\r\n[info] basic_st         Elapsed: 0.41 secs        2,412,483\u002Fsec\r\n[info] rotating_st      Elapsed: 0.72 secs        1,389,196\u002Fsec\r\n[info] daily_st         Elapsed: 0.42 secs        2,393,298\u002Fsec\r\n[info] null_st          Elapsed: 0.04 secs       27,446,957\u002Fsec\r\n[info] **************************************************************\r\n[info] 10 threads, competing over the same logger object, 1,000,000 iterations\r\n[info] **************************************************************\r\n[info] basic_mt         Elapsed: 0.60 secs        1,659,613\u002Fsec\r\n[info] rotating_mt      Elapsed: 0.62 secs        1,612,493\u002Fsec\r\n[info] daily_mt         Elapsed: 0.61 secs        1,638,305\u002Fsec\r\n[info] null_mt          Elapsed: 0.16 secs        6,272,758\u002Fsec\r\n```\r\n#### Asynchronous mode\r\n```\r\n[info] -------------------------------------------------\r\n[info] Messages     : 1,000,000\r\n[info] Threads      : 10\r\n[info] Queue        : 8,192 slots\r\n[info] Queue memory : 8,192 x 272 = 2,176 KB \r\n[info] -------------------------------------------------\r\n[info] \r\n[info] *********************************\r\n[info] Queue Overflow Policy: block\r\n[info] *********************************\r\n[info] Elapsed: 1.70784 secs     585,535\u002Fsec\r\n[info] Elapsed: 1.69805 secs     588,910\u002Fsec\r\n[info] Elapsed: 1.7026 secs      587,337\u002Fsec\r\n[info] \r\n[info] *********************************\r\n[info] Queue Overflow Policy: overrun\r\n[info] *********************************\r\n[info] Elapsed: 0.372816 secs    2,682,285\u002Fsec\r\n[info] Elapsed: 0.379758 secs    2,633,255\u002Fsec\r\n[info] Elapsed: 0.373532 secs    2,677,147\u002Fsec\r\n\r\n```\r\n\r\n## Documentation\r\n\r\nDocumentation can be found in the [wiki](https:\u002F\u002Fgithub.com\u002Fgabime\u002Fspdlog\u002Fwiki) pages.\r\n\r\n---\r\n\r\n### Powered by\r\n\u003Ca href=\"https:\u002F\u002Fjb.gg\u002FOpenSource\">\r\n  \u003Cimg src=\"https:\u002F\u002Fresources.jetbrains.com\u002Fstorage\u002Fproducts\u002Fcompany\u002Fbrand\u002Flogos\u002Fjetbrains.svg\" alt=\"JetBrains logo\" width=\"200\">\r\n\u003C\u002Fa>\r\n","spdlog 是一个高性能的 C++ 日志库。它支持多种日志目标，包括滚动文件、每日文件、控制台（支持颜色）、syslog、Windows 事件日志等，并且可以轻松扩展自定义日志目标。spdlog 的核心功能包括异步模式、丰富的格式化选项（基于 fmt 库）、多线程和单线程日志记录器、运行时和编译时的日志级别过滤以及回溯支持。该项目是头文件独立的，也可以选择编译版本以加快编译速度。spdlog 适用于需要高效日志记录的各种 C++ 项目，特别是在对性能有较高要求的应用场景中。",2,"2026-06-11 03:31:57","trending"]