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}