Very fast, header-only/compiled, C++ logging library.

Install
Header only version
Copy the include 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:
dnf 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
- build2:
depends: spdlog ^1.8.2
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 event log.
- Windows debugger (
OutputDebugString(..)).
- Easily extendable with custom log targets.
- 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
++
{
spdlog::critical(
"Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
spdlog::info(
"Positional args are {1} {0}..",
"too",
"supported");
}
int main(int argc, char *argv[])
void critical(fmt::format_string< Args... > fmt, Args &&...args)
void warn(fmt::format_string< Args... > fmt, Args &&...args)
void error(fmt::format_string< Args... > fmt, Args &&...args)
SPDLOG_INLINE void set_level(level::level_enum log_level)
void info(fmt::format_string< Args... > fmt, Args &&...args)
SPDLOG_INLINE void set_pattern(std::string pattern, pattern_time_type time_type)
void debug(fmt::format_string< Args... > fmt, Args &&...args)
#define SPDLOG_DEBUG(...)
#define SPDLOG_TRACE(...)
Create stdout/stderr logger object
++
void stdout_example()
{
spdlog::get(
"console")->info(
"loggers can be retrieved from a global registry using the spdlog::get(logger_name)");
}
SPDLOG_INLINE std::shared_ptr< logger > get(const std::string &name)
SPDLOG_INLINE std::shared_ptr< logger > stdout_color_mt(const std::string &logger_name, color_mode mode)
SPDLOG_INLINE std::shared_ptr< logger > stderr_color_mt(const std::string &logger_name, color_mode mode)
Basic file logger
++
void basic_logfile_example()
{
try
{
}
{
}
}
const char * what() const SPDLOG_NOEXCEPT override
std::shared_ptr< logger > basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate=false)
Rotating files
++
{
auto max_size = 1048576 * 5;
auto max_files = 3;
}
std::shared_ptr< logger > rotating_logger_mt(const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files, bool rotate_on_open=false)
Daily files
++
{
}
std::shared_ptr< logger > daily_logger_mt(const std::string &logger_name, const filename_t &filename, int hour=0, int minute=0, bool truncate=false, uint16_t max_files=0)
Backtrace support
++
for(int i = 0; i < 100; i++)
{
}
SPDLOG_INLINE void enable_backtrace(size_t n_messages)
SPDLOG_INLINE void dump_backtrace()
Periodic flush
++
SPDLOG_INLINE void flush_every(std::chrono::seconds interval)
Stopwatch
Log binary data in hex
++
{
}
details::dump_info< typename Container::const_iterator > to_hex(const Container &container, size_t size_per_line=32)
Logger with multi sinks - each with different format and log level
++
{
console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v");
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(level::level_enum log_level)
void multi_sink_example()
Asynchronous logging
++
{
auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt");
}
Asynchronous logger with multi sinks
++
void multi_sink_example2()
{
}
SPDLOG_INLINE void register_logger(std::shared_ptr< logger > logger)
std::shared_ptr< spdlog::details::thread_pool > thread_pool()
void init_thread_pool(size_t q_size, size_t thread_count, std::function< void()> on_thread_start)
User defined types
++
{
template<typename OStream>
{
return os <<
"[my_type i=" << c.
i <<
"]";
}
};
{
}
void user_defined_example()
friend OStream & operator<<(OStream &os, const my_type &c)
User defined flags in the log pattern
++
{
public:
{
}
{
return spdlog::details::make_unique<my_formatter_flag>();
}
};
{
}
void custom_flags_example()
SPDLOG_INLINE void set_formatter(std::unique_ptr< spdlog::formatter > formatter)
fmt::basic_memory_buffer< char, 250 > memory_buf_t
Custom error handler
++
{
spdlog::get(
"console")->info(
"some invalid message to trigger an error {}{}{}{}", 3);
}
void err_handler_example()
SPDLOG_INLINE void set_error_handler(void(*handler)(const std::string &msg))
syslog
++
{
syslog_logger->warn("This is warning that will end up in syslog.");
}
std::shared_ptr< logger > syslog_logger_mt(const std::string &logger_name, const std::string &syslog_ident="", int syslog_option=0, int syslog_facility=LOG_USER, bool enable_formatting=false)
Android example
++
void android_example()
{
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
++
int main (
int argc,
char *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