# How to Use Compile-Time Log Levels with SPDLOG_ACTIVE_LEVEL in spdlog

> Master spdlog compile-time log levels with SPDLOG_ACTIVE_LEVEL. Eliminate logging overhead and boost performance by disabling unwanted logs before compilation.

- Repository: [Gabi Melman/spdlog](https://github.com/gabime/spdlog)
- Tags: how-to-guide
- Published: 2026-07-18

---

**Define `SPDLOG_ACTIVE_LEVEL` to a severity constant before including [`spdlog.h`](https://github.com/gabime/spdlog/blob/main/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`](https://github.com/gabime/spdlog/blob/main/include/spdlog/common.h) (lines 41-44), the library defines a default active level if you do not specify one:

```cpp
#ifndef SPDLOG_ACTIVE_LEVEL
    #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
#endif

```

The actual filtering logic resides in [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/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`](https://github.com/gabime/spdlog/blob/main/include/spdlog/common.h):

```cpp
#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:

```cpp
#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:

```bash
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`:

```bash
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:

```cpp
// 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`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h) (lines 78-89) documents the intended usage pattern:

```cpp
// 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`](https://github.com/gabime/spdlog/blob/main/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_LEVEL` defaults to `SPDLOG_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_OFF` eliminates all logging code from the binary.
- **Key files**: [`include/spdlog/common.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/common.h) defines constants; [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h) implements 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`](https://github.com/gabime/spdlog/blob/main/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`](https://github.com/gabime/spdlog/blob/main/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.