spdlog/formatter/mod.rs
1//! Provides formatters for sink formatting log records.
2//!
3//! # Formatter
4//!
5//! Each normal *Sink* owns a *Formatter*, which is used to format each log.
6//!
7//! The default formatter for most sinks is [`FullFormatter`], you can call
8//! [`Sink::set_formatter`] to replace it with another formatter.
9//!
10//! The easiest way to make a custom formatter is to build a pattern, see
11//! [Compile-time and runtime pattern
12//! formatter](#compile-time-and-runtime-pattern-formatter) below. If pattern
13//! isn't flexible enough for you, you need to implement [`Formatter`] trait for
14//! your own formatter struct. See the implementation of [`FullFormatter`] and
15//! [./examples] directory for examples.
16//!
17//! # Compile-time and runtime pattern formatter
18//!
19//! *spdlog-rs* supports formatting your log records according to a pattern
20//! string. There are 2 ways to construct a pattern:
21//!
22//! - Macro [`pattern!`]: Builds a pattern at compile-time.
23//! - Macro [`runtime_pattern!`]: Builds a pattern at runtime.
24//!
25//! ```
26//! use spdlog::formatter::{pattern, PatternFormatter};
27//! # use spdlog::sink::{Sink, WriteSink};
28//!
29//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
30//! // This pattern is built at compile-time, the template accepts only a literal string.
31//! let pattern = pattern!("[{date} {time}.{millisecond}] [{level}] {payload}{eol}");
32//!
33//! #[cfg(feature = "runtime-pattern")]
34//! {
35//! use spdlog::formatter::runtime_pattern;
36//!
37//! // This pattern is built at runtime, the template accepts a runtime string.
38//! let input = "[{date} {time}.{millisecond}] [{level}] {payload}{eol}";
39//! let pattern = runtime_pattern!(input)?;
40//! }
41//!
42//! // Use the compile-time or runtime pattern.
43//! # let your_sink = WriteSink::builder().target(vec![]).build()?;
44//! your_sink.set_formatter(Box::new(PatternFormatter::new(pattern)));
45//! # Ok(()) }
46//! ```
47//!
48//! [`Sink::set_formatter`]: crate::sink::Sink::set_formatter
49//! [./examples]: https://github.com/SpriteOvO/spdlog-rs/tree/main/spdlog/examples
50
51mod full_formatter;
52#[cfg(any(
53 all(target_os = "linux", feature = "native", feature = "libsystemd"),
54 all(doc, not(doctest))
55))]
56mod journald_formatter;
57#[cfg(feature = "serde_json")]
58mod json_formatter;
59mod local_time_cacher;
60mod pattern_formatter;
61
62use std::ops::Range;
63
64use dyn_clone::*;
65pub use full_formatter::*;
66#[cfg(any(
67 all(target_os = "linux", feature = "native", feature = "libsystemd"),
68 all(doc, not(doctest))
69))]
70pub(crate) use journald_formatter::*;
71#[cfg(feature = "serde_json")]
72pub use json_formatter::*;
73pub(crate) use local_time_cacher::*;
74pub use pattern_formatter::*;
75
76use crate::{Record, Result, StringBuf};
77
78/// Represents a formatter that can be used for formatting logs.
79///
80/// # Examples
81///
82/// See the implementation of [`FullFormatter`] and [./examples] directory.
83///
84/// [./examples]: https://github.com/SpriteOvO/spdlog-rs/tree/main/spdlog/examples
85pub trait Formatter: Send + Sync + DynClone {
86 /// Formats a log record.
87 fn format(
88 &self,
89 record: &Record,
90 dest: &mut StringBuf,
91 ctx: &mut FormatterContext,
92 ) -> Result<()>;
93}
94clone_trait_object!(Formatter);
95
96/// Provides context for formatters.
97#[derive(Debug, Default)]
98pub struct FormatterContext<'a> {
99 style_range: Option<Range<usize>>,
100 // Set to `Some` if the cached date time is locked in the upper caller.
101 locked_time_date: Option<TimeDateLazyLocked<'a>>,
102}
103
104impl FormatterContext<'_> {
105 /// Constructs a `FormatterContext`.
106 #[must_use]
107 pub fn new() -> Self {
108 Self {
109 style_range: None,
110 locked_time_date: None,
111 }
112 }
113
114 /// Sets style range (in bytes) of the formatted text.
115 ///
116 /// Users must ensure that indexes are correctly UTF-8 boundary.
117 pub fn set_style_range(&mut self, range: Option<Range<usize>>) {
118 self.style_range = range;
119 }
120
121 /// A style range (in bytes) of the formatted text.
122 ///
123 /// If style is available in the sink, the text in the range will be
124 /// rendered in the style corresponding to that log message level, otherwise
125 /// it will be ignored.
126 ///
127 /// Its indexes are guaranteed by the setter to be the correct UTF-8
128 /// boundary.
129 #[must_use]
130 pub fn style_range(&self) -> Option<Range<usize>> {
131 self.style_range.clone() // This clone is cheap
132 }
133}