SPDLog Pattern Format Specifiers: Complete Guide to Custom Log Formats

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. When you call spdlog::set_pattern(), the library invokes pattern_formatter::compile_pattern_() (implemented in 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
  • 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:

  • %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
  • %# – 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()
#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 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:

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:

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:

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
  • 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.

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. 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.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →