# SPDLog Pattern Format Specifiers: Complete Guide to Custom Log Formats

> Master SPDLog pattern format specifiers to create custom logs. Learn about prefixes like %v and %Y for timestamps, levels, and metadata with alignment controls.

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

---

**SPDLog pattern format specifiers use percent-sign prefixes (like `%v` for messages or `%Y` for years) to inject timestamps, log levels, and metadata into output, with optional padding and truncation controls for precise alignment.**

The `gabime/spdlog` library provides a flexible pattern formatting system that converts log records into formatted strings through compile-time parsing in `pattern_formatter`. Understanding these SPDLog pattern format specifiers enables complete control over log appearance, from thread IDs to source code locations.

## How Pattern Formatting Works in SPDLog

At the core of the formatting system is the `pattern_formatter` class defined in [`include/spdlog/pattern_formatter.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/pattern_formatter.h). When you call `spdlog::set_pattern()`, the library invokes `pattern_formatter::compile_pattern_()` (implemented in [`include/spdlog/pattern_formatter-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/pattern_formatter-inl.h)) to parse the string into a sequence of specialized formatter objects.

The architecture operates through these key components:

- **`pattern_formatter`** – Maintains the raw pattern string, a compiled vector of `flag_formatter` pointers, and custom flag registries
- **`details::flag_formatter`** (abstract base) – Defines the interface for all concrete formatters; receives `log_msg`, `std::tm` time structure, and destination buffer
- **Concrete flag formatters** – Implementations like `level_formatter`, `a_formatter` (short month), `Y_formatter` (4-digit year), and `pid_formatter` located in [`pattern_formatter-inl.h`](https://github.com/gabime/spdlog/blob/main/pattern_formatter-inl.h)
- **`padding_info`** – Captures width, alignment (left/right/center), and truncation settings applied by each formatter during output generation

When a log message is processed, `pattern_formatter::format()` iterates through the compiled list, obtains the current time via `get_time_()`, calls each flag's `format()` method, and appends the configured end-of-line sequence.

## Core Built-In Pattern Format Specifiers

SPDLog supports extensive built-in specifiers defined in [`include/spdlog/pattern_formatter-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/pattern_formatter-inl.h):

- **`%v`** – Log message payload (from `msg.payload`). Example: `Something went wrong`
- **`%+`** – Full default pattern equivalent to `%Y-%m-%d %H:%M:%S.%e %l %n %v`. Example: `2024-07-15 13:42:01.123 info mylogger Something went wrong`
- **`%Y`** – 4-digit year. Example: `2024`
- **`%y`** – 2-digit year. Example: `24`
- **`%m`** – Month as decimal (01-12). Example: `07`
- **`%d`** – Day of month (01-31). Example: `15`
- **`%H`** – Hour in 24-hour format (00-23). Example: `13`
- **`%M`** – Minute (00-59). Example: `42`
- **`%S`** – Second (00-60). Example: `01`
- **`%e`** – Milliseconds (000-999). Example: `123`
- **`%L`** – Log level as full text. Example: `info`
- **`%l`** – Log level as single letter. Example: `I`
- **`%n`** – Logger name. Example: `mylogger`
- **`%t`** – Thread ID (decimal format). Example: `140735689967872`
- **`%T`** – Thread ID in hexadecimal. Example: `0x7ffec3a0`
- **`%p`** – Process ID. Example: `12345`
- **`%r`** – Relative time since logger creation. Example: `00:00:01.234`
- **`%!`** – Source file name (requires `SPDLOG_LOGGER_CALL` macro). Example: [`main.cpp`](https://github.com/gabime/spdlog/blob/main/main.cpp)
- **`%#`** – Source line number. Example: `42`
- **`%*`** – Source function name. Example: `main`

## Padding and Truncation Options

Pattern specifiers support field width and alignment through padding modifiers parsed by `padding_info`. Prefix any specifier with a width number to set minimum field size:

- **`%8l`** – Pads short level to 8 characters (left-aligned by default)
- **`%-8l`** – Pads to 8 characters with right alignment (dash prefix)
- **`%=8l`** – Centers the value in an 8-character field (equals sign prefix)

Truncation removes excess characters when content exceeds the specified width. Add a dot (`.`) before the width specifier:

- **`%.3n`** – Keeps only the first 3 characters of the logger name
- **`%.10v`** – Truncates the log message to 10 characters

Combine both for precise field control: `%-8.8l` creates an 8-character field, right-aligned, truncated to 8 characters maximum.

## Creating Custom Pattern Flags

For application-specific formatting, SPDLog allows runtime extension through the `custom_flag_formatter` base class. Custom flags integrate seamlessly with built-in SPDLog pattern format specifiers.

To implement a custom flag:

1. Inherit from `spdlog::custom_flag_formatter`
2. Override `clone()` to return a `std::unique_ptr<custom_flag_formatter>` to a new instance
3. Override `format()` to write custom content to the destination buffer
4. Register the flag using `pattern_formatter::add_flag()`

```cpp
#include <spdlog/pattern_formatter.h>

class my_flag : public spdlog::custom_flag_formatter {
public:
    std::unique_ptr<custom_flag_formatter> clone() const override {
        return std::make_unique<my_flag>();
    }
    
    void format(const spdlog::details::log_msg&, const std::tm&, 
                spdlog::memory_buf_t& dest) override {
        fmt::format_to(dest, "CUSTOM");
    }
};

// Usage
auto formatter = spdlog::pattern_formatter("%+");
formatter.add_flag<my_flag>('x');
spdlog::set_formatter(std::make_unique<spdlog::pattern_formatter>(formatter));
// Pattern "%x" now outputs "CUSTOM"

```

Reference implementations are available in [`tests/test_pattern_formatter.cpp`](https://github.com/gabime/spdlog/blob/main/tests/test_pattern_formatter.cpp) in the `gabime/spdlog` repository.

## Practical Pattern Configuration Examples

Configure global patterns using `spdlog::set_pattern()` or apply formatters to specific loggers via `logger->set_formatter()`.

**Basic timestamp and level formatting:**

```cpp
spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e [%l] %v");
// Output: 2024-07-15 13:42:01.123 [info] Application started

```

**Padded logger names with truncated thread IDs:**

```cpp
spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e [%10n] [%.5t] %v");
// Output: 2024-07-15 13:42:01.123 [   mylogger] [14073] User logged in

```

**Debug pattern with source location:**

```cpp
spdlog::set_pattern("[%H:%M:%S] [%l] %!:%# %v");

// Output: [13:42:01] [info] main.cpp:42 Processing request

```

## Summary

- **SPDLog pattern format specifiers** begin with `%` and are parsed at formatter construction time by `pattern_formatter::compile_pattern_()` in [`include/spdlog/pattern_formatter-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/pattern_formatter-inl.h)
- **Built-in specifiers** cover timestamps (`%Y`, `%m`, `%d`, `%H`, `%M`, `%S`, `%e`), log levels (`%L`, `%l`), execution context (`%n`, `%t`, `%p`), and source locations (`%!`, `%#`, `%*`)
- **Padding modifiers** (`%8`, `%-8`, `%=8`) and **truncation** (`.8`) control field width and alignment, stored in the `padding_info` struct
- **Custom flags** extend functionality by inheriting from `custom_flag_formatter` and registering via `add_flag()`, enabling domain-specific output without modifying core library code

## Frequently Asked Questions

### How do I align log columns using pattern format specifiers?

Prefix any specifier with a width number to enable padding controlled by the `padding_info` structure. Use `%5l` for left-aligned fixed-width fields, `%-5l` for right-aligned fields, and `%=5l` for centered text. The formatter applies these settings during the `format()` call in [`pattern_formatter-inl.h`](https://github.com/gabime/spdlog/blob/main/pattern_formatter-inl.h).

### What is the difference between `%l` and `%L` in SPDLog patterns?

`%l` outputs the short log level format handled by a compact formatter class (single letter: `I`, `W`, `E`), while `%L` outputs the full level name (`info`, `warning`, `error`). Both are instantiated as separate `flag_formatter` derivatives during pattern compilation in `pattern_formatter::compile_pattern_()`.

### Can I create custom pattern specifiers for SPDLog?

Yes. Create a class inheriting from `spdlog::custom_flag_formatter`, implement the `clone()` and `format()` methods as required by the base class, then register it using `pattern_formatter::add_flag<char>('x', args...)`. Your custom specifier `%x` can then be used alongside built-in specifiers in any pattern string processed by the formatter.

### Where does SPDLog compile the pattern string?

Pattern compilation occurs in `pattern_formatter::compile_pattern_()` within [`include/spdlog/pattern_formatter-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/pattern_formatter-inl.h). This method iterates through the pattern string, identifies percent-sign specifiers, parses optional padding modifiers into `padding_info` objects, and instantiates corresponding `flag_formatter` concrete classes (such as `v_formatter` for `%v` or `Y_formatter` for `%Y`) that populate the internal formatter list executed during log output.