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