CLI tool
gabime/spdlog avatar
gabime/spdlog

spdlog: a fast C++ logging library for header-only or compiled builds

Fast C++ logging library.

29,756 stars5,340 forksC++NOASSERTION

At a glance

What is it?
spdlog is a C++11 logging library that ships as headers or as a compiled library, with sinks for console, rotating files, daily files, syslog and more. This review covers how to add spdlog to a project, how the logger and sink model works, and where it stops being the right choice.
Who is it for?
spdlog fits C++11 codebases that want one logging interface across console, files, syslog and the Windows event log, and it fits best when you take the compiled build to cut compile times. Skip it if you need structured records with typed fields and per-record context, or if you cannot accept that a failed logger construction surfaces as spdlog_ex.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 21 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • gabime/spdlog29,756 ★ · +120
Star history
Repository2026-09-282026-11-14
gabime/spdlog29.6k29.8k

120 Stars in the last 47 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

What spdlog replaces, and for whom

C++ has no logging facility in its standard library, so most projects either grow a printf wrapper or pull in something larger. spdlog occupies the middle: a single interface for console output, files that rotate on size or date, syslog, the Windows event log, and Qt widgets, with formatting delegated to fmt. The README lists the targets explicitly, and each one is a sink you attach to a logger. The intended user is a C++11 project that wants the same call sites on Linux, macOS, Windows and Android. The README lists all four platforms, plus FreeBSD, OpenBSD, Solaris and AIX. That breadth is the reason to pick it over a hand-rolled macro: the call spdlog::info("Welcome to spdlog!") does not change when the sink behind it changes from a color console to a rotating file. If your program logs to one file and never moves, the library is more machinery than the task needs.

Loggers, sinks and the global registry

The model has two layers. A sink is a destination: a stdout color sink, a basic file sink, a rotating file sink, a daily file sink. A logger owns one or more sinks and applies a level and a pattern to what passes through. The README shows both styles. The global default logger is what spdlog::info and spdlog::warn write to, and you change its pattern with spdlog::set_pattern. Named loggers are created through factory functions such as spdlog::stdout_color_mt("console") and spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt"), and the README states they can be retrieved from a global registry with spdlog::get(logger_name). The _mt suffix marks the multi-threaded variant; the README also references single-threaded loggers, and the warning attached to spdlog::flush_every is explicit that it should only be used when all your loggers are thread-safe _mt loggers. That warning is the clearest signal in the README that the threading choice is real and not cosmetic. Compile-time filtering is separate from runtime levels: SPDLOG_TRACE and SPDLOG_DEBUG are removed from release code depending on SPDLOG_ACTIVE_LEVEL, and the README notes this does not change the current log level. Two filtering systems, one runtime and one at compile time, is a design that pays off in hot paths and confuses newcomers in equal measure.

Installing spdlog and writing a first rotating log

The README gives two paths. The header-only version is a copy of the include folder into your build tree with a C++11 compiler. The compiled version is recommended there because it is much faster to compile, and it is built with CMake. On Debian the package is libspdlog-dev; Homebrew, MacPorts, Fedora, Gentoo, Arch, openSUSE, vcpkg, conan and conda all have entries in the README's package manager list.

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

That produces the compiled library. The README points at example/CMakeLists.txt for how to consume it from your own build. A first real use is a rotating file logger, which the README builds with a maximum size in bytes and a count of rotated files:

c++
#include "spdlog/sinks/rotating_file_sink.h"
void rotating_example()
{
    // Create a file rotating logger with 5 MB 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);
}

Run that and you should find logs/rotating.txt on disk, with the file replaced once it passes the size limit. Note the try/catch in the README's basic file logger example: construction can throw spdlog::spdlog_ex, and the README prints ex.what() when it does.

Backtrace buffering and periodic flush

Two features deserve separate attention because they change runtime behaviour rather than formatting. Backtrace support stores debug messages in a ring buffer instead of emitting them. The README calls spdlog::enable_backtrace(32) to keep the latest 32 messages, logs normally in a loop, and then calls spdlog::dump_backtrace() when an error occurs, at which point the buffered messages are written. The same methods exist on a logger instance. This is a memory-for-context trade: you pay for a fixed-size buffer on every message so that a failure report carries the preceding debug trail. The second feature is spdlog::flush_every(std::chrono::seconds(3)), which periodically flushes all registered loggers. The README attaches a warning to it: only use it if all your loggers are thread-safe _mt loggers. Both features are opt-in, and both are easy to enable without reading the caveat that sits next to them.

Where spdlog is the wrong tool

spdlog formats text. If your pipeline needs structured records with typed fields, stable keys and per-record context that a collector can index without parsing, spdlog's message-and-pattern model makes you build that on top of formatted strings. The README's feature list is about targets, formatting, levels and filtering. A second boundary is the exception path. Construction failures surface as spdlog::spdlog_ex, and the README's own file example wraps construction in try/catch. In a codebase that avoids exceptions, that is a mismatch you will feel at every logger creation site. Third, the header-only mode is offered but the README recommends the compiled build because of compile times; if you choose headers for convenience, you are accepting slower builds, and the README says so rather than hiding it. Finally, the global registry is convenient and global: retrieving loggers by name with spdlog::get couples call sites to a string.

spdlog against Boost.Log and glog

Boost.Log is the closest comparison in scope, and the difference is in what you assemble. Boost.Log exposes sources, attributes, filters and sinks as separate configurable pieces, which lets you attach per-record attributes and filter on them in the logging core. spdlog collapses that into a logger plus sinks plus a level, with pattern strings for the rest. If you need attribute-based filtering, Boost.Log models it directly; if you want a logger in three lines, spdlog does. glog takes a third position: it is Google's library with its own severity levels and file naming, and it is not the same interface as spdlog's fmt-style braces. Choosing between them is largely choosing which call syntax and which set of sinks you want to live with, since both write to files and both support severity filtering. The README also credits fmt for the formatting layer, so if you already use fmt, spdlog's format strings will look familiar rather than like a second dialect.

Maintenance, licence and upgrade cost

The repository is not archived, and the last push was on 2026-10-24. Releases in the repository history are v1.17.0 on 2026-01-04, v1.16.0 on 2025-10-11 and v1.15.3 on 2025-05-09, so the version line is still moving. The default branch is v1.x, which means the stable work happens on a versioned branch rather than on a trunk named main. An upgrade is something to verify against your own call sites. The licence field in the repository metadata reads NOASSERTION, which means the automated classifier did not resolve a licence identifier; the repository does contain a LICENSE file at the top level, and that file is the thing to read. This is not legal advice, and the practical implication is simply that you should open LICENSE rather than trust the metadata field, especially if you redistribute the library in a product.

Editorial conclusion

spdlog fits C++11 codebases that want one logging interface across console, files, syslog and the Windows event log, and it fits best when you take the compiled build to cut compile times. Skip it if you need structured records with typed fields and per-record context, or if you cannot accept that a failed logger construction surfaces as spdlog_ex. Before adopting, verify two things in the repository: how the compiled target is named in the CMakeLists.txt, and whether the default logger is registered for the sinks you intend to use.

Frequently asked questions

Is spdlog header only?

Both modes exist. The README says the header-only version is a copy of the include folder into your build tree with a C++11 compiler, and that the compiled version is recommended because it is much faster to compile.

Is spdlog thread safe?

The library provides multi-threaded loggers marked with the _mt suffix, and the README warns that spdlog::flush_every should only be used if all your loggers are thread-safe _mt loggers. It also references single-threaded loggers as a separate option.

How to install spdlog on Ubuntu?

The README lists the Debian package as sudo apt install libspdlog-dev. You can also clone the repository and build the compiled version with CMake, or take the header-only include folder.

What are the different log levels in spdlog?

The README shows trace, debug, info, warn, error and critical calls, and states that levels can be modified at runtime as well as compile time. It also shows spdlog::set_level(spdlog::level::debug) for the global level, and notes that SPDLOG_TRACE and SPDLOG_DEBUG are removed at compile time depending on SPDLOG_ACTIVE_LEVEL without changing the current log level.

How fast is spdlog?

The README describes the library as very fast and points to a benchmarks section, and it recommends the compiled version over header-only partly because of compile times.

How do I add spdlog to a project?

The README's install section builds the compiled library with cmake .. && cmake --build . and points at example/CMakeLists.txt for how to consume it. The repository's top level contains CMakeLists.txt and a cmake/ directory.

Official sources

  1. gabime/spdlog on GitHub
  2. Issues
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/gabime-spdlog.svg)](https://hysenlabs.com/projects/gabime-spdlog)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/gabime-spdlog.svg)](https://hysenlabs.com/projects/gabime-spdlog)

Was this useful?