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