Github url

spdlog

by gabime

gabime /spdlog

Fast C++ logging library.

9.3K Stars 2.0K Forks Last release: 25 days ago (v1.7.0) Other 3.4K Commits 24 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

spdlog

Very fast, header-only/compiled, C++ logging library. Build Status  Build status Release

Install

Header only version

Copy the source folder to your build tree and use a C++11 compiler.

Static lib version (recommended - much faster compile times)

$ git clone https://github.com/gabime/spdlog.git $ cd spdlog && mkdir build && cd build $ cmake .. && make -j

see example CMakeLists.txt on how to use.

Platforms

  • Linux, FreeBSD, OpenBSD, Solaris, AIX
  • Windows (msvc 2013+, cygwin)
  • macOS (clang 3.5+)
  • Android

Package managers:

  • Homebrew:
    brew install spdlog
  • MacPorts:
    sudo port install spdlog
  • FreeBSD:
    cd /usr/ports/devel/spdlog/ && make install clean
  • Fedora:
    yum install spdlog
  • Gentoo:
    emerge dev-libs/spdlog
  • Arch Linux:
    pacman -S spdlog
  • vcpkg:
    vcpkg install spdlog
  • conan:
    spdlog/[\>=1.4.1]
  • conda:
    conda install -c conda-forge spdlog

Features

  • Very fast (see benchmarks below).
  • Headers only or compiled
  • Feature rich formatting, using the excellent fmt library.
  • Asynchronous mode (optional)
  • Custom formatting.
  • Multi/Single threaded loggers.
  • Various log targets:
    • Rotating log files.
    • Daily log files.
    • Console logging (colors supported).
    • syslog.
    • Windows debugger (
      OutputDebugString(..)
      )
    • Easily extendable with custom log targets (just implement a single function in the sink interface).
  • Log filtering - log levels can be modified in runtime as well as in compile time.
  • Support for loading log levels from argv or from environment var.
  • Backtrace support - store debug messages in a ring buffer and display later on demand.

Usage samples

Basic usage

#include "spdlog/spdlog.h" #include "spdlog/sinks/basic\_file\_sink.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 // define SPDLOG\_ACTIVE\_LEVEL to desired level SPDLOG\_TRACE("Some trace message with param {}", 42); SPDLOG\_DEBUG("Some debug message"); // Set the default logger to file logger auto file\_logger = spdlog::basic\_logger\_mt("basic\_logger", "logs/basic.txt"); spdlog::set\_default\_logger(file\_logger); }

Create stdout/stderr logger object

#include "spdlog/spdlog.h" #include "spdlog/sinks/stdout\_color\_sinks.h" 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)"); }

Basic file logger

#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; } }

Rotating files

#include "spdlog/sinks/rotating\_file\_sink.h" void rotating\_example() { // Create a file rotating logger with 5mb size max and 3 rotated files 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); }

Daily files

#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 logger = spdlog::daily\_logger\_mt("daily\_logger", "logs/daily.txt", 2, 30); }

Backtrace support

// Loggers can store in a ring buffer all messages (including debug/trace) and display later on demand. // When needed, call dump\_backtrace() to see them spdlog::enable\_backtrace(32); // Store the latest 32 messages in a buffer. Older messages will be dropped. // or my\_logger-\>enable\_backtrace(32).. for(int i = 0; i \< 100; i++) { spdlog::debug("Backtrace message {}", i); // not logged yet.. } // e.g. if some error happened: spdlog::dump\_backtrace(); // log them now! show the last 32 messages // or my\_logger-\>dump\_backtrace(32)..

Periodic flush

// periodically flush all \*registered\* loggers every 3 seconds: // warning: only use if all your loggers are thread safe ("\_mt" loggers) spdlog::flush\_every(std::chrono::seconds(3));

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> buf;
    console-&gt;info("Binary example: {}", spdlog::to_hex(buf));
    console-&gt;info("Another binary example:{:n}", spdlog::to_hex(std::begin(buf), std::begin(buf) + 10));
    // more examples:
    // logger-&gt;info("uppercase: {:X}", spdlog::to_hex(buf));
    // logger-&gt;info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf));
    // logger-&gt;info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf));
}

</char></char>

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<:sinks::stdout_color_sink_mt>();
    console_sink-&gt;set_level(spdlog::level::warn);
    console_sink-&gt;set_pattern("[multi_sink_example] [%^%l%$] %v");

    auto file_sink = std::make_shared<:sinks::basic_file_sink_mt>("logs/multisink.txt", true);
    file_sink-&gt;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");
}
</:sinks::basic_file_sink_mt></:sinks::stdout_color_sink_mt>

Asynchronous logging

#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<:async_factory>("async_file_logger", "logs/async_log.txt");
    // alternatively:
    // auto async_file = spdlog::create_async<:sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");   
}

</:sinks::basic_file_sink_mt></:async_factory>

Asynchronous logger with multi sinks

#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<:sinks::stdout_color_sink_mt>();
    auto rotating_sink = std::make_shared<:sinks::rotating_file_sink_mt>("mylog.txt", 1024*1024*10, 3);
    std::vector<:sink_ptr> sinks {stdout_sink, rotating_sink};
    auto logger = std::make_shared<:async_logger>("loggername", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block);
    spdlog::register_logger(logger);
}
</:async_logger></:sink_ptr></:sinks::rotating_file_sink_mt></:sinks::stdout_color_sink_mt>

User defined types

// 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 &amp;operator&lt;info("user defined type: {}", my_type{14});
}

</typename>

User defined flags in the log pattern

// Log patterns can contain custom flags. // the following example will add new flag '%\*' - which will be bound to a <my_formatter_flag> instance.
#include "spdlog/pattern_formatter.h"
class my_formatter_flag : public spdlog::custom_flag_formatter
{
public:
    void format(const spdlog::details::log_msg &amp;, const std::tm &amp;, spdlog::memory_buf_t &amp;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()
{    
    auto formatter = std::make_unique<:pattern_formatter>();
    formatter-&gt;add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v");
    spdlog::set_formatter(std::move(formatter));
}

</my_formatter_flag></:pattern_formatter></my_formatter_flag></custom_flag_formatter></my_formatter_flag>

Custom error handler

void err\_handler\_example() { // can be set globally or per logger(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 example

#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."); }

Load log levels from env variable or from argv

#include "spdlog/cfg/env.h" int main (int argc, char \*argv[]) { spdlog::cfg::load\_env\_levels(); // 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(argc, argv); }

So then you can:

$ export SPDLOG\_LEVEL=info,mylogger=trace $ ./example

Benchmarks

Below are some benchmarks done in Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz

Synchronous mode

[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

Asynchronous mode

[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

Documentation

Documentation can be found in the wiki pages.


Thanks to JetBrains for donating product licenses to help develop spdlog

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.