spdlog/formatter/
full_formatter.rs1use std::fmt::{self, Write};
4
5use crate::{
6 formatter::{fmt_with_time, Formatter, FormatterContext, TimeDate},
7 Error, Record, StringBuf, __EOL,
8};
9
10#[rustfmt::skip]
11#[derive(Clone)]
35pub struct FullFormatter {
36 with_eol: bool,
37}
38
39impl FullFormatter {
40 #[must_use]
42 pub fn new() -> FullFormatter {
43 FullFormatter { with_eol: true }
44 }
45
46 #[must_use]
47 pub(crate) fn without_eol() -> Self {
48 Self { with_eol: false }
49 }
50
51 fn format_impl(
52 &self,
53 record: &Record,
54 dest: &mut StringBuf,
55 ctx: &mut FormatterContext,
56 ) -> Result<(), fmt::Error> {
57 #[cfg(not(feature = "flexible-string"))]
58 dest.reserve(crate::string_buf::RESERVE_SIZE);
59
60 fmt_with_time(
61 ctx,
62 record,
63 |mut time: TimeDate| -> Result<(), fmt::Error> {
64 dest.write_str("[")?;
65 dest.write_str(time.full_second_str())?;
66 dest.write_str(".")?;
67 write!(dest, "{:03}", time.millisecond())?;
68 dest.write_str("] [")?;
69 Ok(())
70 },
71 )?;
72
73 if let Some(logger_name) = record.logger_name() {
74 dest.write_str(logger_name)?;
75 dest.write_str("] [")?;
76 }
77
78 let style_range_begin = dest.len();
79
80 dest.write_str(record.level().as_str())?;
81
82 let style_range_end = dest.len();
83
84 if let Some(srcloc) = record.source_location() {
85 dest.write_str("] [")?;
86 dest.write_str(srcloc.module_path())?;
87 dest.write_str(", ")?;
88 dest.write_str(srcloc.file())?;
89 dest.write_str(":")?;
90 write!(dest, "{}", srcloc.line())?;
91 }
92
93 dest.write_str("] ")?;
94 dest.write_str(record.payload())?;
95
96 record.key_values().write_to(dest, true)?;
97
98 if self.with_eol {
99 dest.write_str(__EOL)?;
100 }
101
102 ctx.set_style_range(Some(style_range_begin..style_range_end));
103 Ok(())
104 }
105}
106
107impl Formatter for FullFormatter {
108 fn format(
109 &self,
110 record: &Record,
111 dest: &mut StringBuf,
112 ctx: &mut FormatterContext,
113 ) -> crate::Result<()> {
114 self.format_impl(record, dest, ctx)
115 .map_err(Error::FormatRecord)
116 }
117}
118
119impl Default for FullFormatter {
120 fn default() -> FullFormatter {
121 FullFormatter::new()
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use chrono::prelude::*;
128
129 use super::*;
130 use crate::{kv, Level, __EOL};
131
132 #[test]
133 fn format() {
134 let kvs = [
135 (kv::Key::__from_static_str("k1"), kv::Value::from(114)),
136 (kv::Key::__from_static_str("k2"), kv::Value::from("514")),
137 ];
138 let record = Record::new(Level::Warn, "test log content", None, None, &kvs);
139 let mut buf = StringBuf::new();
140 let mut ctx = FormatterContext::new();
141 FullFormatter::new()
142 .format(&record, &mut buf, &mut ctx)
143 .unwrap();
144
145 let local_time: DateTime<Local> = record.time().into();
146 assert_eq!(
147 format!(
148 "[{}] [warn] test log content {{ k1=114 k2=514 }}{}",
149 local_time.format("%Y-%m-%d %H:%M:%S.%3f"),
150 __EOL
151 ),
152 buf
153 );
154 assert_eq!(Some(27..31), ctx.style_range());
155 }
156}