spdlog/formatter/
full_formatter.rs

1//! Provides a full info formatter.
2
3use std::fmt::{self, Write};
4
5use cfg_if::cfg_if;
6
7use crate::{
8    formatter::{fmt_with_time, Formatter, FormatterContext, TimeDate},
9    Error, Record, StringBuf, __EOL,
10};
11
12#[rustfmt::skip]
13/// Full information logs formatter.
14///
15/// It is the default formatter for most sinks.
16///
17/// Log messages formatted by it look like:
18///
19///  - Default:
20///
21///    <pre>
22///    [2022-11-02 09:23:12.263] [<font color="#0DBC79">info</font>] hello, world!
23///    </pre>
24///
25///  - If the logger has a name:
26///
27///    <pre>
28///    [2022-11-02 09:23:12.263] [logger-name] [<font color="#0DBC79">info</font>] hello, world!
29///    </pre>
30/// 
31///  - If crate feature `source-location` is enabled:
32///
33///    <pre>
34///    [2022-11-02 09:23:12.263] [logger-name] [<font color="#0DBC79">info</font>] [mod::path, src/main.rs:4] hello, world!
35///    </pre>
36#[derive(Clone)]
37pub struct FullFormatter {
38    with_eol: bool,
39}
40
41impl FullFormatter {
42    /// Constructs a `FullFormatter`.
43    #[must_use]
44    pub fn new() -> FullFormatter {
45        FullFormatter { with_eol: true }
46    }
47
48    #[must_use]
49    pub(crate) fn without_eol() -> Self {
50        Self { with_eol: false }
51    }
52
53    fn format_impl(
54        &self,
55        record: &Record,
56        dest: &mut StringBuf,
57        ctx: &mut FormatterContext,
58    ) -> Result<(), fmt::Error> {
59        cfg_if! {
60            if #[cfg(not(feature = "flexible-string"))] {
61                dest.reserve(crate::string_buf::RESERVE_SIZE);
62            }
63        }
64
65        fmt_with_time(ctx, record, |mut time: TimeDate| {
66            dest.write_str("[")?;
67            dest.write_str(time.full_second_str())?;
68            dest.write_str(".")?;
69            write!(dest, "{:03}", time.millisecond())?;
70            dest.write_str("] [")?;
71            Ok(())
72        })?;
73
74        if let Some(logger_name) = record.logger_name() {
75            dest.write_str(logger_name)?;
76            dest.write_str("] [")?;
77        }
78
79        let style_range_begin = dest.len();
80
81        dest.write_str(record.level().as_str())?;
82
83        let style_range_end = dest.len();
84
85        if let Some(srcloc) = record.source_location() {
86            dest.write_str("] [")?;
87            dest.write_str(srcloc.module_path())?;
88            dest.write_str(", ")?;
89            dest.write_str(srcloc.file())?;
90            dest.write_str(":")?;
91            write!(dest, "{}", srcloc.line())?;
92        }
93
94        dest.write_str("] ")?;
95        dest.write_str(record.payload())?;
96
97        if self.with_eol {
98            dest.write_str(__EOL)?;
99        }
100
101        ctx.set_style_range(Some(style_range_begin..style_range_end));
102        Ok(())
103    }
104}
105
106impl Formatter for FullFormatter {
107    fn format(
108        &self,
109        record: &Record,
110        dest: &mut StringBuf,
111        ctx: &mut FormatterContext,
112    ) -> crate::Result<()> {
113        self.format_impl(record, dest, ctx)
114            .map_err(Error::FormatRecord)
115    }
116}
117
118impl Default for FullFormatter {
119    fn default() -> FullFormatter {
120        FullFormatter::new()
121    }
122}
123
124#[cfg(test)]
125mod tests {
126    use chrono::prelude::*;
127
128    use super::*;
129    use crate::{Level, __EOL};
130
131    #[test]
132    fn format() {
133        let record = Record::new(Level::Warn, "test log content", None, None);
134        let mut buf = StringBuf::new();
135        let mut ctx = FormatterContext::new();
136        FullFormatter::new()
137            .format(&record, &mut buf, &mut ctx)
138            .unwrap();
139
140        let local_time: DateTime<Local> = record.time().into();
141        assert_eq!(
142            format!(
143                "[{}] [warn] test log content{}",
144                local_time.format("%Y-%m-%d %H:%M:%S.%3f"),
145                __EOL
146            ),
147            buf
148        );
149        assert_eq!(Some(27..31), ctx.style_range());
150    }
151}