How to Integrate spdlog into a C++ Project: Header-Only and Compiled Setup Guide

Add spdlog to your project via CMake by linking against spdlog::spdlog for compiled mode or spdlog::spdlog_header_only for header-only mode, then include <spdlog/spdlog.h> to start logging.

The spdlog library by gabime/spdlog provides a fast, thread-safe logging solution for modern C++ applications. Whether you need a simple console logger or a high-throughput rotating file system, learning how to integrate spdlog into a C++ project is straightforward using either header-only or compiled library approaches.

Installation Methods: Header-Only vs. Compiled

Spdlog offers two consumption models. The header-only mode exposes all implementation in include/spdlog/ and requires defining SPDLOG_HEADER_ONLY before includes. The compiled mode builds libspdlog.a or spdlog.dll via the provided CMakeLists.txt, moving heavy template instantiation into a pre-built binary to reduce compile times.

Header-Only Integration

For header-only usage, copy the include/spdlog directory into your project or add the repository as a Git submodule. Define the preprocessor macro to ensure inline definitions are available:

#define SPDLOG_HEADER_ONLY
#include <spdlog/spdlog.h>

Compiled Library Integration

For the compiled approach, add spdlog as a subdirectory in your CMake build. This method utilizes the build targets defined in CMakeLists.txt and links the implementation from src/spdlog.cpp and src/async.cpp:

add_subdirectory(spdlog)
target_link_libraries(MyApp PRIVATE spdlog::spdlog)

Alternatively, use the header-only CMake target without manually defining macros:

target_link_libraries(MyApp PRIVATE spdlog::spdlog_header_only)

Basic Usage with the Default Logger

Once integrated, the fastest way to start logging is through the global default logger, defined in include/spdlog/spdlog.h. This logger writes to stdout with color support and is available immediately without explicit construction:

#include <spdlog/spdlog.h>

int main() {
    spdlog::info("Application started");
    spdlog::error("Critical value: {}", 42);
    spdlog::set_level(spdlog::level::debug);
    spdlog::debug("Debug output enabled");
}

Creating Custom Loggers

For production applications, instantiate named logger objects managed by the global registry in include/spdlog/details/registry.h. This allows retrieval via spdlog::get(name) across translation units.

Console Loggers

Create colorized console loggers using sinks defined in include/spdlog/sinks/stdout_color_sinks.h:

#include <spdlog/sinks/stdout_color_sinks.h>

auto console = spdlog::stdout_color_mt("console");
console->info("Named console logger ready");
spdlog::get("console")->warn("Retrieved from registry");

File and Rotating Loggers

For persistent storage, use the rotating file sink from include/spdlog/sinks/rotating_file_sink.h. The implementation in src/file_sinks.cpp handles rotation logic:

#include <spdlog/sinks/rotating_file_sink.h>

const std::size_t max_size = 5 * 1024 * 1024; // 5 MiB
const std::size_t max_files = 3;
auto rotating = spdlog::rotating_logger_mt("rotating", "logs/app.txt", max_size, max_files);
rotating->info("Rotating logger initialized");

For daily rotation at a specific time, use spdlog::daily_logger_mt from the daily file sink header.

Advanced Configuration Patterns

Asynchronous Logging

High-throughput applications benefit from the async logger implemented in include/spdlog/async_logger.h and src/async.cpp. Initialize a thread pool via spdlog::init_thread_pool() before creating async loggers:

#include <spdlog/async.h>
#include <spdlog/sinks/basic_file_sink.h>

spdlog::init_thread_pool(8192, 1); // queue size, worker threads
auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async", "logs/async.txt");
async_file->info("Non-blocking log entry");

Multi-Sink Configuration

Route messages to multiple destinations with distinct formatting by combining sinks from include/spdlog/sinks/. Each sink maintains its own log level and pattern:

#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>

auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
console_sink->set_level(spdlog::level::warn);

auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/full.txt", true);
file_sink->set_level(spdlog::level::trace);

spdlog::logger multi("multi", {console_sink, file_sink});
multi.info("Visible in file only; console shows warn and above");

Environment-Based Level Configuration

Dynamically adjust verbosity without recompiling by using the configuration helper in include/spdlog/cfg/env.h:

#include <spdlog/cfg/env.h>

spdlog::cfg::load_env_levels(); // Reads SPDLOG_LEVEL environment variable
spdlog::debug("Level controlled by environment");

Summary

  • spdlog provides both header-only and compiled integration modes via CMakeLists.txt targets spdlog::spdlog and spdlog::spdlog_header_only.
  • Include <spdlog/spdlog.h> to access the default logger or use specific headers like <spdlog/sinks/rotating_file_sink.h> for advanced sinks.
  • The core logger class in include/spdlog/logger.h manages sinks and formatting, while include/spdlog/details/registry.h enables global logger retrieval.
  • Enable high-performance logging using the async logger with spdlog::init_thread_pool() defined in src/async.cpp.
  • Configure runtime behavior through environment variables using spdlog::cfg::load_env_levels().

Frequently Asked Questions

What is the difference between header-only and compiled spdlog?

The header-only mode requires adding the include/ directory to your path and defining SPDLOG_HEADER_ONLY, compiling all template code in your translation units. The compiled mode links against libspdlog.a built from src/spdlog.cpp, reducing compilation time for large projects by pre-building the heavy formatting logic.

How do I change the log level at runtime?

Call spdlog::set_level(spdlog::level::debug) on the logger instance or the global default logger. For environment-driven configuration, use spdlog::cfg::load_env_levels() from include/spdlog/cfg/env.h to parse the SPDLOG_LEVEL variable.

Can I use spdlog in a multi-threaded application?

Yes. All spdlog sinks provided in include/spdlog/sinks/ are thread-safe by default, utilizing the _mt (multi-threaded) suffix. The registry in include/spdlog/details/registry.h is also thread-safe for registering and retrieving loggers concurrently.

How do I create a logger that writes to both console and file?

Instantiate multiple sinks, such as stdout_color_sink_mt and basic_file_sink_mt, and pass them to the spdlog::logger constructor. Each sink can have independent log levels and formatting patterns, allowing fine-grained control over output destinations.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →