Skip to main content

Pattern flags

The pattern controls the line around your message — timestamp, level, logger name, thread id — and it's set per logger or per sink, not per call. You write spdlog::info("connected") once; the pattern decides whether that becomes connected or [2026-08-07 14:02:11.123] [app] [info] connected.

Setting a pattern

spdlog::set_pattern(...) sets the pattern for every registered logger; logger->set_pattern(...) sets it for one logger's sinks that don't have their own override; sink->set_pattern(...) sets it for that sink specifically. The most specific one wins — a sink-level pattern always overrides whatever the logger or global call set. See Multi-sink loggers for why that matters when different sinks want different layouts.

The flag table

FlagMeaningExample output
%vThe actual log messageconnection refused
%nLogger nameapp
%lLevel, full nameinfo
%LLevel, short (single letter)I
%tThread id140735
%PProcess id4242
%YYear, 4 digits2026
%mMonth, 2 digits08
%dDay, 2 digits07
%HHour, 24h14
%MMinute02
%SSecond11
%eMillisecond123
%fMicrosecond123456
%FNanosecond123456789
%zUTC offset+00:00
%+spdlog's full default format[2026-08-07 14:02:11.123] [app] [info] connected
%@Source location (file:line)main.cpp:42
%sSource filename, basename onlymain.cpp
%#Source line number42
%!Source function namehandle_request

Color range

%^ and %$ bound the span a color sink actually colors — everything outside that range prints in the terminal's default color regardless of level:

sink->set_pattern("[%H:%M:%S] %^[%l]%$ %v"); // only "[info]" (etc.) gets colored

Padding and alignment

Width specifiers between % and the flag pad or truncate: %-8l left-justifies the level name in an 8-character field; %8n right-justifies the logger name in 8 characters.

Cost

Every flag in a pattern is work performed on every message that passes both the logger and sink level filters — timestamps in particular involve a syscall-backed clock read.

%s/%# only carry a value if you use the SPDLOG_* macros

Calling spdlog::info(...) directly never populates source location — %s, %#, %!, and %@ render empty unless the call went through SPDLOG_INFO(...) or one of the other SPDLOG_* macros. See Source location and structured logging for why.

A short list to start from:

  • Dev, human-readable: "[%H:%M:%S] %^[%l]%$ %v" — fast to scan, colored, no date noise.
  • Production, machine-parseable: a fixed-width, unambiguous format that log tooling can split on.
  • Minimal console: "%v" — just the message, for tools that already prefix their own timestamp.
A production pattern worth copying
[%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v

Full timestamp to the millisecond, logger name, level, message — sortable, greppable, and unambiguous across timezones if you also fix the process to UTC.

See also