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}