# SPDLog Macros Explained: Compile-Time Logging Control in C++

> Master SPDLog macros for powerful compile-time logging control in C++. Achieve zero-cost filtering and auto source location capture with this essential guide.

- Repository: [Gabi Melman/spdlog](https://github.com/gabime/spdlog)
- Tags: deep-dive
- Published: 2026-07-15

---

**SPDLog macros provide zero-cost compile-time filtering by expanding to logging calls when enabled or to no-ops when disabled, automatically capturing source location and supporting both default and custom logger instances.**

All logging macros in the [gabime/spdlog](https://github.com/gabime/spdlog) repository are defined in [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h), wrapping the core `logger` API to eliminate boilerplate while maintaining high performance. Understanding these **SPDLog macros** is essential for configuring compile-time verbosity levels and optimizing release builds.

## How SPDLog Macros Work at Compile Time

The macro system relies on conditional compilation to remove disabled logging statements entirely from the binary. This happens before the C++ compiler generates machine code, ensuring that suppressed log levels incur absolutely no runtime overhead.

### The Role of SPDLOG_ACTIVE_LEVEL

The `SPDLOG_ACTIVE_LEVEL` macro acts as a global verbosity gate. Defined before including [`spdlog.h`](https://github.com/gabime/spdlog/blob/main/spdlog.h), it determines which severity levels remain in the compiled binary.

```cpp
// Enable debug-level logging at compile time
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG
#include "spdlog/spdlog.h"

```

Each logging macro checks against this value using preprocessor conditionals. For example, in [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h) around lines 292–311, the debug macros are guarded by:

```cpp
#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG
// Macro definitions active
#else
#define SPDLOG_DEBUG(...) (void)0
#endif

```

When the condition fails, the macro expands to `(void)0`, which the compiler optimizes away completely.

### Source Location Capture with SPDLOG_FUNCTION

By default, SPDLog macros automatically capture file, line, and function information. The internal `SPDLOG_LOGGER_CALL` macro constructs a `spdlog::source_loc` object:

```cpp
#define SPDLOG_LOGGER_CALL(logger, level, ...) \
    (logger)->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__)

```

This captures `__FILE__` and `__LINE__` from the preprocessor, along with `SPDLOG_FUNCTION` (which resolves to `__func__` or compiler-specific equivalents). To disable this overhead, define `SPDLOG_NO_SOURCE_LOC` before including the header, causing the macro to omit the source location payload.

## The Two Macro Families

SPDLog provides parallel macro sets for every severity level: `trace`, `debug`, `info`, `warn`, `error`, `critical`, and `off`. These divide into two categories based on the target logger.

### SPDLOG_LOGGER_<LEVEL> Macros

These macros target a specific logger instance passed as the first argument. They expand to the `log()` method on that instance:

```cpp
auto file_logger = spdlog::basic_logger_mt("filelog", "app.log");
SPDLOG_LOGGER_WARN(file_logger, "Low disk space warning: {}% remaining", 5);

```

In [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h), `SPDLOG_LOGGER_DEBUG` expands to:

```cpp
#define SPDLOG_LOGGER_DEBUG(logger, ...) \
    SPDLOG_LOGGER_CALL(logger, spdlog::level::debug, __VA_ARGS__)

```

This pattern applies to all severity levels, delegating to `SPDLOG_LOGGER_CALL` with the appropriate `spdlog::level` enum value.

### SPDLOG_<LEVEL> Macros

These convenience macros route to the **default logger** (`spdlog::default_logger_raw()`), eliminating the need to pass a logger pointer explicitly:

```cpp
SPDLOG_INFO("Application started successfully");
// Expands to:
// SPDLOG_LOGGER_INFO(spdlog::default_logger_raw(), "Application started successfully")

```

The default logger typically writes to stdout. If no default logger exists, these macros safely handle the null case.

## Compile-Time Optimization and Zero-Cost Abstractions

The macro system achieves zero-cost abstraction through several mechanisms:

1. **Conditional compilation** — Disabled levels compile to no-ops
2. **Inline expansion** — Macros inline directly to `logger->log()` calls without function call overhead
3. **Compile-time formatting checks** — When using `fmt` integration, format strings are validated at compile time

Define `SPDLOG_NO_SOURCE_LOC` in [`include/spdlog/tweakme.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/tweakme.h) or as a compiler flag to remove source location storage, reducing binary size and per-log overhead in performance-critical paths.

## Practical Configuration Examples

**Enable debug logging in development:**

```cpp
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG
#include "spdlog/spdlog.h"

int main() {
    spdlog::set_level(spdlog::level::debug); // Runtime level
    
    SPDLOG_DEBUG("Variable x = {}", 42);     // Compiled and executed
    SPDLOG_TRACE("Deep trace");             // Compiled but filtered at runtime
}

```

**Use custom loggers for specific modules:**

```cpp
auto network_logger = spdlog::basic_logger_mt("network", "network.log");
SPDLOG_LOGGER_INFO(network_logger, "Connection established: {}", ip_address);

```

**Strip all logging for release builds:**

```cpp
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_OFF
#include "spdlog/spdlog.h"
// All SPDLOG_* macros now expand to (void)0

```

## Summary

- **SPDLog macros** are defined in [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h) and wrap the core `logger::log()` API
- **`SPDLOG_ACTIVE_LEVEL`** controls compile-time filtering, eliminating disabled statements from the binary
- **Two macro families** exist: `SPDLOG_<LEVEL>()` for the default logger, and `SPDLOG_LOGGER_<LEVEL>()` for custom instances
- **Source location** is captured automatically via `__FILE__`, `__LINE__`, and `SPDLOG_FUNCTION`, unless disabled with `SPDLOG_NO_SOURCE_LOC`
- **Zero runtime overhead** occurs when logging levels are disabled at compile time

## Frequently Asked Questions

### What is SPDLOG_ACTIVE_LEVEL?

`SPDLOG_ACTIVE_LEVEL` is a preprocessor macro that sets the minimum logging severity included in the compilation. Valid values range from `SPDLOG_LEVEL_TRACE` (0) to `SPDLOG_LEVEL_OFF` (6). Any logging macro with a severity level lower than the active level expands to `(void)0` and is removed by the compiler. Define this macro before including [`spdlog.h`](https://github.com/gabime/spdlog/blob/main/spdlog.h).

### How do I disable source location tracking?

Define `SPDLOG_NO_SOURCE_LOC` before including [`spdlog.h`](https://github.com/gabime/spdlog/blob/main/spdlog.h). This causes all logging macros to omit the `spdlog::source_loc` parameter, reducing per-log overhead and binary size. This is useful in release builds where file and line information is not required. The definition can be placed in [`include/spdlog/tweakme.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/tweakme.h) or passed as a compiler flag (`-DSPDLOG_NO_SOURCE_LOC`).

### What is the difference between SPDLOG_INFO and SPDLOG_LOGGER_INFO?

`SPDLOG_INFO(...)` logs to the default logger obtained via `spdlog::default_logger_raw()`, requiring no logger argument. `SPDLOG_LOGGER_INFO(logger, ...)` accepts a specific logger instance as its first argument, routing the message to that sink. The latter is essential when using multiple loggers for different subsystems or output destinations.

### Do SPDLog macros have runtime overhead when disabled?

No. When `SPDLOG_ACTIVE_LEVEL` is set higher than a specific macro's level (e.g., set to `WARN` while using `SPDLOG_DEBUG`), the preprocessor replaces the macro with `(void)0`. The compiler optimizes this away completely, resulting in zero instructions and no runtime cost. This is why SPDLog macros are preferred over runtime-checked logging in performance-critical C++ applications.