pattern!() { /* proc-macro */ }
Expand description
Builds a pattern from a template literal string at compile-time.
It accepts inputs in the form:
// This is not exactly a valid declarative macro, just for intuition.
macro_rules! pattern {
( $template:literal $(,)? ) => {};
( $template:literal, $( {$$custom:ident} => $ctor:expr ),+ $(,)? ) => {};
}
Examples of valid inputs:
pattern!("text");
pattern!("current line: {line}{eol}");
pattern!("custom: {$my_pattern}{eol}", {$my_pattern} => MyPattern::default);
Its first argument accepts only a literal string that is known at compile-time.
If you want to build a pattern from a runtime string, use
runtime_pattern!
macro instead.
§Note
The value returned by this macro is implementation details and users should not access them. If these details are changed in the future, it may not be considered as a breaking change.
§Basic Usage
In its simplest form, pattern
receives a literal template string and
converts it into a zero-cost pattern:
use spdlog::formatter::{pattern, PatternFormatter};
let formatter = PatternFormatter::new(pattern!("template string"));
§Using Built-in Patterns
A pattern that always outputs a fixed string is boring and useless.
Luckily, the pattern template string can contain placeholders that
represents built-in patterns. For example, to include the log level and
payload in the pattern, we can simply use {level}
and {payload}
in the
pattern template string:
use spdlog::info;
let formatter = PatternFormatter::new(pattern!("[{level}] {payload}{eol}"));
info!(logger: doctest, "Interesting log message");
/* Output */ "[info] Interesting log message\n"
Here, {level}
and {payload}
are “placeholders” that will be replaced by
the output of the corresponding built-in patterns when formatting log
records.
What if you want to output a literal {
or }
character? Simply use {{
and }}
:
let formatter = PatternFormatter::new(pattern!("[{{escaped}}] {payload}{eol}"));
info!(logger: doctest, "Interesting log message");
/* Output */ "[{escaped}] Interesting log message\n"
You can find a full list of all built-in patterns and their corresponding placeholders at Appendix below.
§Using Style Range
A specific portion of a formatted log message can be specified as “style
range”. Formatted text in the style range will be rendered in a different
style by supported sinks. You can use {^...}
to mark the style range in
the pattern template string:
let formatter = PatternFormatter::new(pattern!("{^[{level}]} {payload}{eol}"));
info!(logger: doctest, "Interesting log message");
/* Output */ "[info] Interesting log message\n"
// ^^^^^^ <- style range
§Using Your Own Patterns
Yes, you can refer your own implementation of Pattern
in the pattern
template string! Let’s say you have a struct that implements the
Pattern
trait. To refer MyPattern
in the pattern template string, you
need to use the extended syntax to associate MyPattern
with a name so
that pattern!
can resolve it:
use std::fmt::Write;
use spdlog::{
formatter::{pattern, Pattern, PatternContext, PatternFormatter},
Record, StringBuf, info
};
#[derive(Default, Clone)]
struct MyPattern;
impl Pattern for MyPattern {
fn format(&self, record: &Record, dest: &mut StringBuf, _: &mut PatternContext) -> spdlog::Result<()> {
write!(dest, "My own pattern").map_err(spdlog::Error::FormatRecord)
}
}
let pat = pattern!("[{level}] {payload} - {$mypat}{eol}",
{$mypat} => MyPattern::default,
);
let formatter = PatternFormatter::new(pat);
info!(logger: doctest, "Interesting log message");
/* Output */ "[info] Interesting log message - My own pattern\n"
Note the special {$name} => id
syntax given to the pattern
macro.
name
is the name of your own pattern; placeholder {$name}
in the
template string will be replaced by the output of your own pattern. name
can only be an identifier. id
is a path that identifies a function
that can be called with no arguments. Instances of your own pattern
will be created by calling this function with no arguments.
§Custom Pattern Creation
Each placeholder results in a new pattern instance. For example, consider a
custom pattern that writes a unique ID to the output. If the pattern
template string contains multiple placeholders that refer to MyPattern
,
each placeholder will eventually be replaced by different IDs.
static NEXT_ID: AtomicU32 = AtomicU32::new(0);
#[derive(Clone)]
struct MyPattern {
id: u32,
}
impl MyPattern {
fn new() -> Self {
Self {
id: NEXT_ID.fetch_add(1, Ordering::Relaxed),
}
}
}
impl Pattern for MyPattern {
fn format(&self, record: &Record, dest: &mut StringBuf, _: &mut PatternContext) -> spdlog::Result<()> {
write!(dest, "{}", self.id).map_err(spdlog::Error::FormatRecord)
}
}
let pat = pattern!("[{level}] {payload} - {$mypat} {$mypat} {$mypat}{eol}",
{$mypat} => MyPattern::new,
);
let formatter = PatternFormatter::new(pat);
info!(logger: doctest, "Interesting log message");
/* Output */ "[info] Interesting log message - 0 1 2\n"
Of course, you can have multiple custom patterns:
let pat = pattern!("[{level}] {payload} - {$mypat} {$myotherpat}{eol}",
{$mypat} => MyPattern::default,
{$myotherpat} => MyOtherPattern::default,
);
§Name Conflicts are Hard Errors
It’s a hard error if names of your own custom pattern conflicts with other patterns:
let pattern = pattern!("[{level}] {payload} - {$mypat}{eol}",
{$mypat} => MyPattern::new,
// Error: name conflicts with another custom pattern
{$mypat} => MyOtherPattern::new,
);
let pattern = pattern!("[{level}] {payload} - {$day}{eol}",
// Error: name conflicts with a built-in pattern
{$day} => MyPattern::new,
);
§Appendix: Full List of Built-in Patterns
Placeholders | Description | Example |
---|---|---|
{weekday_name} | Abbreviated weekday name | Mon , Tue |
{weekday_name_full} | Weekday name | Monday , Tuesday |
{month_name} | Abbreviated month name | Jan , Feb |
{month_name_full} | Month name | January , February |
{datetime} | Full date time | Thu Aug 23 15:35:46 2014 |
{year_short} | Short year | 22 , 20 |
{year} | Year | 2022 , 2021 |
{date_short} | Short date | 04/01/22 , 12/31/21 |
{date} | Date (ISO 8601) | 2022-04-01 , 2021-12-31 |
{month} | Month | 01 , 12 |
{day} | Day in month | 01 , 12 , 31 , 30 |
{hour} | Hour in 24-hour | 01 , 12 , 23 |
{hour_12} | Hour in 12-hour | 01 , 12 |
{minute} | Minute | 00 , 05 , 59 |
{second} | Second | 00 , 05 , 59 |
{millisecond} | Millisecond | 231 |
{microsecond} | Microseconds within a second | 372152 |
{nanosecond} | Nanoseconds within a second | 482930154 |
{am_pm} | AM / PM | AM , PM |
{time_12} | Time in 12-hour format | 02:55:02 PM |
{time_short} | Short time | 22:28 , 09:53 |
{time} | Time | 22:28:02 , 09:53:41 |
{tz_offset} | Timezone offset | +08:00 , +00:00 , -06:00 |
{unix_timestamp} | Unix timestamp | 1528834770 |
{full} | Full log message | See FullFormatter |
{level} | Log level | critical , error , warn |
{level_short} | Short log level | C , E , W |
{source} | Source file and line | path/to/main.rs:30 1 |
{file_name} | Source file name | main.rs 1 |
{file} | Source file path | path/to/main.rs 1 |
{line} | Source file line | 30 1 |
{column} | Source file column | 20 1 |
{module_path} | Source module path | mod::module 1 |
{logger} | Logger name | my-logger |
{payload} | Log payload | log message |
{pid} | Process ID | 3824 |
{tid} | Thread ID | 3132 |
{eol} | End of line | \n (on non-Windows) or \r\n (on Windows) |
Patterns related to source location require that feature
source-location
is enabled, otherwise the output is empty. ↩