spdlog

repository·v1.x·Indexed 12 days ago

https://github.com/gabime/spdlog

A high-performance C++ logging library designed for speed and flexibility. It supports header-only and compiled modes, provides rich formatting via the fmt library, and offers various output targets including rotating and daily files, console, syslog, and Windows event logs. Features include asynchronous logging, backtrace support, Mapped Diagnostic Context (MDC), and the ability to load log levels from environment variables or command-line arguments.

Tokens
3.7K
Snippets
13
Records
15
Agent score
49%

What's inside spdlog

  1. Overview of spdlog features

    v1.x

    spdlog is a fast C++ logging library with the following capabilities:

    • Performance: Extremely fast, with optional asynchronous mode.
    • Formatting: Uses the fmt library for feature-rich formatting and supports custom formatting.
    • Concurrency: Supports both multi-threaded and single-threaded loggers.
    • Log Targets (Sinks):
      • Rotating log files
      • Daily log files
      • Console logging (with color support)
      • syslog
      • Windows event log
      • Windows debugger (OutputDebugString(..))
      • Qt widgets
      • Custom sinks (extensible)
    • Filtering: Log levels can be modified at both runtime and compile time. Supports loading levels from argv or environment variables.
    • Backtrace Support: Stores debug messages in a ring buffer to be displayed on demand.
  2. Create a logger with multiple sinks

    v1.x

    A single logger can target multiple destinations (sinks), each with its own log level and formatting pattern. For example, you can configure a console sink to only show warn level messages with a specific pattern, while a file sink logs everything from trace level with a different pattern.

    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");
  3. Use Mapped Diagnostic Context (MDC)

    v1.x

    Mapped Diagnostic Context (MDC) allows you to store key-value pairs in thread-local storage. These pairs can be automatically appended to log outputs using the %& formatter in your log pattern.

    Note: MDC is not supported in asynchronous mode because it relies on thread-local storage.

    Use spdlog::mdc::put("key", "value") to add entries.

    #include "spdlog/mdc.h"
    
    void mdc_example()
    {
        spdlog::mdc::put("key1", "value1");
        spdlog::mdc::put("key2", "value2");
        // Use pattern: spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [%&] %v");
    }
  4. Use backtrace support for debug messages

    v1.x

    Backtrace support allows you to store recent debug messages in a ring buffer without immediately writing them to the log. This is useful for seeing the context leading up to an error. You enable it with spdlog::enable_backtrace(buffer_size) and dump the stored messages using spdlog::dump_backtrace(). This can be applied globally or to a specific logger instance.

    spdlog::enable_backtrace(32); // Store the latest 32 messages in a buffer.
    for(int i = 0; i < 100; i++)
    {
      spdlog::debug("Backtrace message {}", i); // not logged yet..
    }
    // if an error happens:
    spdlog::dump_backtrace(); // log them now!
  5. Install spdlog as a compiled library

    v1.x

    The compiled version is recommended because it significantly improves compilation times. You can build it using CMake following these steps:

    1. Clone the repository.
    2. Create a build directory.
    3. Run CMake and build the project.

    Refer to example/CMakeLists.txt in the repository for integration details.

    $ git clone https://github.com/gabime/spdlog.git
    $ cd spdlog && mkdir build && cd build
    $ cmake .. && cmake --build .
  6. Install spdlog as a header-only library

    v1.x

    To use spdlog without a formal build step, copy the include/spdlog directory from the repository into your project's include path. You must use a C++11 compatible compiler.

    # Copy the include/spdlog folder to your build tree
  7. Basic usage of spdlog

    v1.x

    spdlog provides a simple API for logging messages at various levels (info, error, warn, critical, debug, trace). It uses Python-style formatting (via the {} syntax) for arguments. You can set the global log level using spdlog::set_level() and customize the output format using spdlog::set_pattern(). For performance, you can use compile-time log levels with macros like SPDLOG_TRACE and SPDLOG_DEBUG, which can be stripped from release builds depending on the SPDLOG_ACTIVE_LEVEL definition.

    #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); // Set *global* log level to debug
        spdlog::debug("This message should be displayed..");    
        
        // change log pattern
        spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v");
        
        // Compile time log levels
        SPDLOG_TRACE("Some trace message with param {}", 42);
        SPDLOG_DEBUG("Some debug message");
    }
  8. Configure asynchronous logging

    v1.x

    Asynchronous logging offloads the logging work to a background thread pool to minimize latency in the application thread.

    1. Initialize the thread pool using spdlog::init_thread_pool(queue_size, thread_count).
    2. Create an async logger using the spdlog::async_factory template parameter or spdlog::create_async<SinkType>(...).

    Example using async_factory:

    auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
    #include "spdlog/async.h"
    #include "spdlog/sinks/basic_file_sink.h"
    
    void async_example()
    {
        // spdlog::init_thread_pool(8192, 1); 
        auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
    }
  9. Install spdlog via package managers

    v1.x

    You can install spdlog using various system and cross-platform package managers:

    ManagerCommand
    Debiansudo apt install libspdlog-dev
    Homebrewbrew install spdlog
    MacPortssudo port install spdlog
    FreeBSDpkg install spdlog
    Fedoradnf install spdlog
    Gentooemerge dev-libs/spdlog
    Arch Linuxpacman -S spdlog
    openSUSEsudo zypper in spdlog-devel
    ALT Linuxapt-get install libspdlog-devel
    vcpkgvcpkg install spdlog
    conanconan install --requires=spdlog/[*]
    condaconda install -c conda-forge spdlog
    build2depends: spdlog ^1.8.2
  10. Load log levels from environment variables or arguments

    v1.x

    You can dynamically set log levels for different loggers using environment variables or command-line arguments.

    • Environment Variables: Use spdlog::cfg::load_env_levels(). You can specify a custom variable name with spdlog::cfg::load_env_levels("MYAPP_LEVEL"). The format is LEVEL,logger_name=LEVEL (e.g., info,mylogger=trace).
    • Command Line Arguments: Use spdlog::cfg::load_argv_levels(argc, argv) to load levels from the command line.
    #include "spdlog/cfg/env.h"
    
    int main (int argc, char *argv[])
    {
        spdlog::cfg::load_env_levels();
        // Example env var: export SPDLOG_LEVEL=info,mylogger=trace
    }
  11. Create stdout and stderr loggers

    v1.x

    You can create colorized console loggers for standard output or standard error using spdlog::stdout_color_mt(name) and spdlog::stderr_color_mt(name). Loggers can be retrieved from the global registry at any time using spdlog::get(logger_name). The _mt suffix indicates a multi-threaded safe logger.

    #include "spdlog/spdlog.h"
    #include "spdlog/sinks/stdout_color_sinks.h"
    void stdout_example()
    {
        // create a 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)");
    }
  12. Log binary data in hex format

    v1.x

    You can log binary data (like std::array<char> or ranges) in a hex format using spdlog::to_hex().

    Supported format flags within the curly braces:

    • {:X}: Print in uppercase.
    • {:s}: Don't separate each byte with a space.
    • {:p}: Don't print the position on each line start.
    • {:n}: Don't split the output into lines.
    • {:a}: Show ASCII if {:n} is not set.
    #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));
    }