How spdlog Integrates with the fmt Library for Formatting Arguments
spdlog delegates all string formatting to the fmt library by bundling it inside spdlog/fmt/ and using fmt::vformat_to for zero-copy log message construction.
The gabime/spdlog repository builds its entire logging API on top of the fmt library (formerly cppformat). This integration allows spdlog to provide type-safe, high-performance formatting without reimplementing string formatting logic. Whether you're logging simple values or complex custom patterns, fmt handles the heavy lifting under the hood.
Bundled fmt Header Structure
spdlog includes a complete bundled copy of fmt in the include/spdlog/fmt/ directory. This vendored approach ensures consistent behavior across platforms and eliminates external dependencies.
The primary re-export point is spdlog/fmt/fmt.h. This header simply includes the corresponding fmt header and brings its symbols into the spdlog namespace:
#include <spdlog/fmt/fmt.h>
// Use fmt directly through spdlog's bundled version
auto msg = spdlog::fmt::format("Hex: {:#x}", 255); // equivalent to fmt::format
Users can write spdlog::fmt::format(...) or rely on the default fmt::format calls used internally throughout the library. This design keeps the public API clean while maintaining full access to fmt's capabilities.
Core Log Message Formatting: logger.h
When you call any logging function, spdlog captures variadic arguments using fmt's format-argument list and forwards them for direct buffer writing.
In include/spdlog/logger.h (around line 336), the logger class implements the formatting pipeline:
// Example usage
auto logger = spdlog::stdout_color_mt("console");
int value = 42;
logger->info("The answer is {}", value); // fmt::vformat_to invoked internally
The internal flow works as follows:
- Argument capture – Variadic arguments are wrapped with
fmt::make_format_args - Zero-copy formatting –
fmt::vformat_towrites directly intospdlog::memory_buf_t - Avoided allocations – No temporary
std::stringobjects are created during formatting
This approach maximizes performance by eliminating intermediate string copies, which matters significantly for high-throughput logging scenarios.
Pattern Formatting with fmt
The pattern_formatter—responsible for timestamps, thread IDs, log levels, and other metadata—also relies on fmt internally. Found in include/spdlog/pattern_formatter-inl.h, this component:
- Parses the user-provided pattern string (e.g.,
"[%Y-%m-%d %H:%M:%S.%e] [%l] %v") - Builds an internal fmt format string representing the pattern structure
- Calls
fmt::format_toto embed pattern-expanded elements into the final log line
// Custom pattern using fmt internally
spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");
spdlog::info("Formatted with custom pattern");
The pattern system leverages fmt's formatting specifiers for date/time components while maintaining spdlog's specialized syntax for log-specific fields like %l (level) and %v (message).
Compile-Time Format String Safety
spdlog inherits fmt's compile-time format string checking through the FMT_STRING macro. This feature catches mismatched format specifiers at compile time rather than runtime.
The implementation resides in include/spdlog/fmt/bundled/compile.h (around line 35). When enabled, code like this produces a compile error:
// Compile-time error: format specifier mismatch
logger->info(FMT_STRING("Value: {}"), "string", 42); // too many arguments
logger->info(FMT_STRING("Value: {0:d}"), "not a number"); // type mismatch
This safety guarantee extends automatically to all spdlog users without requiring explicit opt-in for basic cases.
Key Integration Files
| File | Role |
|---|---|
include/spdlog/fmt/fmt.h |
Re-exports bundled fmt API for public use |
include/spdlog/logger.h |
Implements logger class with fmt::vformat_to usage |
include/spdlog/pattern_formatter-inl.h |
Pattern parsing and fmt-based final formatting |
include/spdlog/fmt/bundled/compile.h |
Compile-time format string checking via FMT_STRING |
include/spdlog/spdlog.h |
Public entry point that pulls in fmt headers |
Summary
- spdlog bundles fmt directly in
spdlog/fmt/to eliminate external dependencies - All log formatting flows through fmt::vformat_to for zero-copy buffer writing
- The pattern_formatter uses fmt internally for timestamp and metadata expansion
- Compile-time safety comes via fmt's
FMT_STRINGmacro with automatic type checking - Users can access fmt directly through
spdlog::fmt::format()when needed
Frequently Asked Questions
Can I use my system-installed fmt instead of spdlog's bundled version?
Yes. spdlog supports both bundled and external fmt through CMake options. Set SPDLOG_FMT_EXTERNAL=ON during configuration to link against a system-installed fmt library rather than the vendored copy.
Does spdlog support fmt's compile-time format strings by default?
Basic compile-time checking works automatically with FMT_STRING. For full compile-time format string optimization (where the format is parsed at compile time), you need to include the appropriate headers and use FMT_COMPILE macros from spdlog/fmt/compile.h.
What fmt version does spdlog bundle?
The bundled fmt version varies by spdlog release. Check include/spdlog/fmt/bundled/core.h for the FMT_VERSION macro to determine the exact version included in your spdlog installation.
Is there any performance overhead from spdlog's fmt integration?
No—spdlog's fmt integration adds no overhead compared to using fmt directly. The fmt::vformat_to path used in logger.h is the same high-performance approach recommended for direct fmt usage, with pre-allocated buffers avoiding all dynamic allocations during normal operation.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →