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}