How to Use Compile-Time Log Levels with SPDLOG_ACTIVE_LEVEL in spdlog
Define SPDLOG_ACTIVE_LEVEL to a severity constant before including spdlog.h to eliminate logging calls below that level at compile time, resulting in zero runtime overhead for disabled levels.
The spdlog library (gabime/spdlog) provides a powerful compile-time mechanism to strip out logging code entirely using the SPDLOG_ACTIVE_LEVEL macro. By setting this macro to a specific severity threshold, you instruct the preprocessor to replace unwanted logging calls with no-ops, removing them completely from the compiled binary. This technique is essential for production builds where performance and binary size matter.
How Compile-Time Log Levels Work in spdlog
The mechanism operates through preprocessor directives in two key headers. In include/spdlog/common.h (lines 41-44), the library defines a default active level if you do not specify one:
#ifndef SPDLOG_ACTIVE_LEVEL
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
#endif
The actual filtering logic resides in include/spdlog/spdlog.h (lines 99-152). Here, the library compares SPDLOG_ACTIVE_LEVEL against each severity constant. If a logging macro corresponds to a level higher than the active threshold, it expands to (void)0, becoming a no-operation. When the level is less than or equal to SPDLOG_ACTIVE_LEVEL, the macro expands to a real function call that forwards to the logger (lines 298-347).
Because the compiler sees (void)0 instead of function calls for disabled levels, it optimizes away all associated code—eliminating runtime checks, string formatting, and function call overhead.
Configuring SPDLOG_ACTIVE_LEVEL
You must define SPDLOG_ACTIVE_LEVEL before any #include <spdlog/spdlog.h> statement. The library recognizes these constants defined in include/spdlog/common.h:
#define SPDLOG_LEVEL_TRACE 0
#define SPDLOG_LEVEL_DEBUG 1
#define SPDLOG_LEVEL_INFO 2
#define SPDLOG_LEVEL_WARN 3
#define SPDLOG_LEVEL_ERROR 4
#define SPDLOG_LEVEL_CRITICAL 5
#define SPDLOG_LEVEL_OFF 6
Method 1: Define in the Source File
Add a #define directive before including the header to enable debugging for that specific translation unit:
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG
#include <spdlog/spdlog.h>
int main() {
SPDLOG_TRACE("trace details"); // Compiled: 0 ≤ 1
SPDLOG_DEBUG("debug info"); // Compiled: 1 ≤ 1
SPDLOG_INFO("standard info"); // Compiled: 2 > 1 (but still active due to logic)
}
Method 2: Define via Compiler Flag (Recommended)
For large projects, pass the definition during compilation to apply it globally without modifying source files:
g++ -DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_INFO -I./include main.cpp -o main
With this flag, SPDLOG_TRACE and SPDLOG_DEBUG macros expand to (void)0 throughout the entire build, while SPDLOG_INFO and higher remain active.
Method 3: Disable All Logging
To remove every logging call—including critical errors—from your release binary, set the level to SPDLOG_LEVEL_OFF:
g++ -DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_OFF -I./include main.cpp -o main
All macros (SPDLOG_TRACE through SPDLOG_CRITICAL) become no-ops, completely removing spdlog code from the resulting binary.
Method 4: Per-File Override
You can mix compile-time levels across translation units by defining the macro selectively. Set a project-wide default via compiler flags, then override in specific debug-heavy files:
// debug_utils.cpp
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE
#include <spdlog/spdlog.h>
void verbose_diagnostics() {
SPDLOG_TRACE("entering function"); // Active only in this file
}
Implementation Details in Source Files
The header comment in include/spdlog/spdlog.h (lines 78-89) documents the intended usage pattern:
// enable/disable log calls at compile time according to global level.
// define SPDLOG_ACTIVE_LEVEL to one of those (before including spdlog.h):
// SPDLOG_LEVEL_TRACE,
// SPDLOG_LEVEL_DEBUG,
// SPDLOG_LEVEL_INFO,
// SPDLOG_LEVEL_WARN,
// SPDLOG_LEVEL_ERROR,
// SPDLOG_LEVEL_CRITICAL,
// SPDLOG_LEVEL_OFF
For reference implementations, see include/spdlog/tweakme.h, which contains example overrides (commented out) showing how users typically customize this setting in their projects.
Summary
- Zero-cost abstraction: Disabled log levels compile to
(void)0, removing all runtime overhead. - Default behavior: If undefined,
SPDLOG_ACTIVE_LEVELdefaults toSPDLOG_LEVEL_INFO(level 2). - Scope control: Define via compiler flags for global settings or in specific files for localized debugging.
- Complete removal: Setting
SPDLOG_LEVEL_OFFeliminates all logging code from the binary. - Key files:
include/spdlog/common.hdefines constants;include/spdlog/spdlog.himplements the conditional macro logic.
Frequently Asked Questions
What is the default SPDLOG_ACTIVE_LEVEL if I do not define it?
According to the source code in include/spdlog/common.h (lines 41-44), the library defaults to SPDLOG_LEVEL_INFO when SPDLOG_ACTIVE_LEVEL is undefined. This means trace and debug logging macros expand to no-ops unless you explicitly request a lower threshold.
How do I completely remove logging code from my release binary?
Define SPDLOG_ACTIVE_LEVEL as SPDLOG_LEVEL_OFF before including spdlog headers. When set to level 6 (off), every logging macro—including critical errors—expands to (void)0, causing the compiler to generate zero logging-related code in the final executable.
Can I set different compile-time log levels for different source files?
Yes. By defining SPDLOG_ACTIVE_LEVEL before #include <spdlog/spdlog.h> in specific translation units, you can enable verbose tracing in debug utilities while maintaining higher thresholds (like SPDLOG_LEVEL_WARN) in performance-critical modules. This per-file granularity allows surgical control over binary size and logging verbosity.
What happens to disabled log macros at compile time?
Disabled macros expand to the expression (void)0 as implemented in include/spdlog/spdlog.h (lines 99-152). This is a C++ idiom that explicitly discards any value while satisfying the compiler's requirement for a valid expression. The optimizer subsequently removes these statements entirely, eliminating both the logging call and any associated string literal or formatting overhead.
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 →