1336d762aSopenharmony_ci//! Formatting for log records.
2336d762aSopenharmony_ci//!
3336d762aSopenharmony_ci//! This module contains a [`Formatter`] that can be used to format log records
4336d762aSopenharmony_ci//! into without needing temporary allocations. Usually you won't need to worry
5336d762aSopenharmony_ci//! about the contents of this module and can use the `Formatter` like an ordinary
6336d762aSopenharmony_ci//! [`Write`].
7336d762aSopenharmony_ci//!
8336d762aSopenharmony_ci//! # Formatting log records
9336d762aSopenharmony_ci//!
10336d762aSopenharmony_ci//! The format used to print log records can be customised using the [`Builder::format`]
11336d762aSopenharmony_ci//! method.
12336d762aSopenharmony_ci//! Custom formats can apply different color and weight to printed values using
13336d762aSopenharmony_ci//! [`Style`] builders.
14336d762aSopenharmony_ci//!
15336d762aSopenharmony_ci//! ```
16336d762aSopenharmony_ci//! use std::io::Write;
17336d762aSopenharmony_ci//!
18336d762aSopenharmony_ci//! let mut builder = env_logger::Builder::new();
19336d762aSopenharmony_ci//!
20336d762aSopenharmony_ci//! builder.format(|buf, record| {
21336d762aSopenharmony_ci//!     writeln!(buf, "{}: {}",
22336d762aSopenharmony_ci//!         record.level(),
23336d762aSopenharmony_ci//!         record.args())
24336d762aSopenharmony_ci//! });
25336d762aSopenharmony_ci//! ```
26336d762aSopenharmony_ci//!
27336d762aSopenharmony_ci//! [`Formatter`]: struct.Formatter.html
28336d762aSopenharmony_ci//! [`Style`]: struct.Style.html
29336d762aSopenharmony_ci//! [`Builder::format`]: ../struct.Builder.html#method.format
30336d762aSopenharmony_ci//! [`Write`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html
31336d762aSopenharmony_ci
32336d762aSopenharmony_ciuse std::cell::RefCell;
33336d762aSopenharmony_ciuse std::fmt::Display;
34336d762aSopenharmony_ciuse std::io::prelude::*;
35336d762aSopenharmony_ciuse std::rc::Rc;
36336d762aSopenharmony_ciuse std::{fmt, io, mem};
37336d762aSopenharmony_ci
38336d762aSopenharmony_ciuse log::Record;
39336d762aSopenharmony_ci
40336d762aSopenharmony_cimod humantime;
41336d762aSopenharmony_cipub(crate) mod writer;
42336d762aSopenharmony_ci
43336d762aSopenharmony_cipub use self::humantime::glob::*;
44336d762aSopenharmony_cipub use self::writer::glob::*;
45336d762aSopenharmony_ci
46336d762aSopenharmony_ciuse self::writer::{Buffer, Writer};
47336d762aSopenharmony_ci
48336d762aSopenharmony_cipub(crate) mod glob {
49336d762aSopenharmony_ci    pub use super::{Target, TimestampPrecision, WriteStyle};
50336d762aSopenharmony_ci}
51336d762aSopenharmony_ci
52336d762aSopenharmony_ci/// Formatting precision of timestamps.
53336d762aSopenharmony_ci///
54336d762aSopenharmony_ci/// Seconds give precision of full seconds, milliseconds give thousands of a
55336d762aSopenharmony_ci/// second (3 decimal digits), microseconds are millionth of a second (6 decimal
56336d762aSopenharmony_ci/// digits) and nanoseconds are billionth of a second (9 decimal digits).
57336d762aSopenharmony_ci#[derive(Copy, Clone, Debug)]
58336d762aSopenharmony_cipub enum TimestampPrecision {
59336d762aSopenharmony_ci    /// Full second precision (0 decimal digits)
60336d762aSopenharmony_ci    Seconds,
61336d762aSopenharmony_ci    /// Millisecond precision (3 decimal digits)
62336d762aSopenharmony_ci    Millis,
63336d762aSopenharmony_ci    /// Microsecond precision (6 decimal digits)
64336d762aSopenharmony_ci    Micros,
65336d762aSopenharmony_ci    /// Nanosecond precision (9 decimal digits)
66336d762aSopenharmony_ci    Nanos,
67336d762aSopenharmony_ci}
68336d762aSopenharmony_ci
69336d762aSopenharmony_ci/// The default timestamp precision is seconds.
70336d762aSopenharmony_ciimpl Default for TimestampPrecision {
71336d762aSopenharmony_ci    fn default() -> Self {
72336d762aSopenharmony_ci        TimestampPrecision::Seconds
73336d762aSopenharmony_ci    }
74336d762aSopenharmony_ci}
75336d762aSopenharmony_ci
76336d762aSopenharmony_ci/// A formatter to write logs into.
77336d762aSopenharmony_ci///
78336d762aSopenharmony_ci/// `Formatter` implements the standard [`Write`] trait for writing log records.
79336d762aSopenharmony_ci/// It also supports terminal colors, through the [`style`] method.
80336d762aSopenharmony_ci///
81336d762aSopenharmony_ci/// # Examples
82336d762aSopenharmony_ci///
83336d762aSopenharmony_ci/// Use the [`writeln`] macro to format a log record.
84336d762aSopenharmony_ci/// An instance of a `Formatter` is passed to an `env_logger` format as `buf`:
85336d762aSopenharmony_ci///
86336d762aSopenharmony_ci/// ```
87336d762aSopenharmony_ci/// use std::io::Write;
88336d762aSopenharmony_ci///
89336d762aSopenharmony_ci/// let mut builder = env_logger::Builder::new();
90336d762aSopenharmony_ci///
91336d762aSopenharmony_ci/// builder.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args()));
92336d762aSopenharmony_ci/// ```
93336d762aSopenharmony_ci///
94336d762aSopenharmony_ci/// [`Write`]: https://doc.rust-lang.org/stable/std/io/trait.Write.html
95336d762aSopenharmony_ci/// [`writeln`]: https://doc.rust-lang.org/stable/std/macro.writeln.html
96336d762aSopenharmony_ci/// [`style`]: #method.style
97336d762aSopenharmony_cipub struct Formatter {
98336d762aSopenharmony_ci    buf: Rc<RefCell<Buffer>>,
99336d762aSopenharmony_ci    write_style: WriteStyle,
100336d762aSopenharmony_ci}
101336d762aSopenharmony_ci
102336d762aSopenharmony_ciimpl Formatter {
103336d762aSopenharmony_ci    pub(crate) fn new(writer: &Writer) -> Self {
104336d762aSopenharmony_ci        Formatter {
105336d762aSopenharmony_ci            buf: Rc::new(RefCell::new(writer.buffer())),
106336d762aSopenharmony_ci            write_style: writer.write_style(),
107336d762aSopenharmony_ci        }
108336d762aSopenharmony_ci    }
109336d762aSopenharmony_ci
110336d762aSopenharmony_ci    pub(crate) fn write_style(&self) -> WriteStyle {
111336d762aSopenharmony_ci        self.write_style
112336d762aSopenharmony_ci    }
113336d762aSopenharmony_ci
114336d762aSopenharmony_ci    pub(crate) fn print(&self, writer: &Writer) -> io::Result<()> {
115336d762aSopenharmony_ci        writer.print(&self.buf.borrow())
116336d762aSopenharmony_ci    }
117336d762aSopenharmony_ci
118336d762aSopenharmony_ci    pub(crate) fn clear(&mut self) {
119336d762aSopenharmony_ci        self.buf.borrow_mut().clear()
120336d762aSopenharmony_ci    }
121336d762aSopenharmony_ci}
122336d762aSopenharmony_ci
123336d762aSopenharmony_ciimpl Write for Formatter {
124336d762aSopenharmony_ci    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
125336d762aSopenharmony_ci        self.buf.borrow_mut().write(buf)
126336d762aSopenharmony_ci    }
127336d762aSopenharmony_ci
128336d762aSopenharmony_ci    fn flush(&mut self) -> io::Result<()> {
129336d762aSopenharmony_ci        self.buf.borrow_mut().flush()
130336d762aSopenharmony_ci    }
131336d762aSopenharmony_ci}
132336d762aSopenharmony_ci
133336d762aSopenharmony_ciimpl fmt::Debug for Formatter {
134336d762aSopenharmony_ci    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135336d762aSopenharmony_ci        f.debug_struct("Formatter").finish()
136336d762aSopenharmony_ci    }
137336d762aSopenharmony_ci}
138336d762aSopenharmony_ci
139336d762aSopenharmony_cipub(crate) type FormatFn = Box<dyn Fn(&mut Formatter, &Record) -> io::Result<()> + Sync + Send>;
140336d762aSopenharmony_ci
141336d762aSopenharmony_cipub(crate) struct Builder {
142336d762aSopenharmony_ci    pub format_timestamp: Option<TimestampPrecision>,
143336d762aSopenharmony_ci    pub format_module_path: bool,
144336d762aSopenharmony_ci    pub format_target: bool,
145336d762aSopenharmony_ci    pub format_level: bool,
146336d762aSopenharmony_ci    pub format_indent: Option<usize>,
147336d762aSopenharmony_ci    pub custom_format: Option<FormatFn>,
148336d762aSopenharmony_ci    pub format_suffix: &'static str,
149336d762aSopenharmony_ci    built: bool,
150336d762aSopenharmony_ci}
151336d762aSopenharmony_ci
152336d762aSopenharmony_ciimpl Default for Builder {
153336d762aSopenharmony_ci    fn default() -> Self {
154336d762aSopenharmony_ci        Builder {
155336d762aSopenharmony_ci            format_timestamp: Some(Default::default()),
156336d762aSopenharmony_ci            format_module_path: false,
157336d762aSopenharmony_ci            format_target: true,
158336d762aSopenharmony_ci            format_level: true,
159336d762aSopenharmony_ci            format_indent: Some(4),
160336d762aSopenharmony_ci            custom_format: None,
161336d762aSopenharmony_ci            format_suffix: "\n",
162336d762aSopenharmony_ci            built: false,
163336d762aSopenharmony_ci        }
164336d762aSopenharmony_ci    }
165336d762aSopenharmony_ci}
166336d762aSopenharmony_ci
167336d762aSopenharmony_ciimpl Builder {
168336d762aSopenharmony_ci    /// Convert the format into a callable function.
169336d762aSopenharmony_ci    ///
170336d762aSopenharmony_ci    /// If the `custom_format` is `Some`, then any `default_format` switches are ignored.
171336d762aSopenharmony_ci    /// If the `custom_format` is `None`, then a default format is returned.
172336d762aSopenharmony_ci    /// Any `default_format` switches set to `false` won't be written by the format.
173336d762aSopenharmony_ci    pub fn build(&mut self) -> FormatFn {
174336d762aSopenharmony_ci        assert!(!self.built, "attempt to re-use consumed builder");
175336d762aSopenharmony_ci
176336d762aSopenharmony_ci        let built = mem::replace(
177336d762aSopenharmony_ci            self,
178336d762aSopenharmony_ci            Builder {
179336d762aSopenharmony_ci                built: true,
180336d762aSopenharmony_ci                ..Default::default()
181336d762aSopenharmony_ci            },
182336d762aSopenharmony_ci        );
183336d762aSopenharmony_ci
184336d762aSopenharmony_ci        if let Some(fmt) = built.custom_format {
185336d762aSopenharmony_ci            fmt
186336d762aSopenharmony_ci        } else {
187336d762aSopenharmony_ci            Box::new(move |buf, record| {
188336d762aSopenharmony_ci                let fmt = DefaultFormat {
189336d762aSopenharmony_ci                    timestamp: built.format_timestamp,
190336d762aSopenharmony_ci                    module_path: built.format_module_path,
191336d762aSopenharmony_ci                    target: built.format_target,
192336d762aSopenharmony_ci                    level: built.format_level,
193336d762aSopenharmony_ci                    written_header_value: false,
194336d762aSopenharmony_ci                    indent: built.format_indent,
195336d762aSopenharmony_ci                    suffix: built.format_suffix,
196336d762aSopenharmony_ci                    buf,
197336d762aSopenharmony_ci                };
198336d762aSopenharmony_ci
199336d762aSopenharmony_ci                fmt.write(record)
200336d762aSopenharmony_ci            })
201336d762aSopenharmony_ci        }
202336d762aSopenharmony_ci    }
203336d762aSopenharmony_ci}
204336d762aSopenharmony_ci
205336d762aSopenharmony_ci#[cfg(feature = "termcolor")]
206336d762aSopenharmony_citype SubtleStyle = StyledValue<'static, &'static str>;
207336d762aSopenharmony_ci#[cfg(not(feature = "termcolor"))]
208336d762aSopenharmony_citype SubtleStyle = &'static str;
209336d762aSopenharmony_ci
210336d762aSopenharmony_ci/// The default format.
211336d762aSopenharmony_ci///
212336d762aSopenharmony_ci/// This format needs to work with any combination of crate features.
213336d762aSopenharmony_cistruct DefaultFormat<'a> {
214336d762aSopenharmony_ci    timestamp: Option<TimestampPrecision>,
215336d762aSopenharmony_ci    module_path: bool,
216336d762aSopenharmony_ci    target: bool,
217336d762aSopenharmony_ci    level: bool,
218336d762aSopenharmony_ci    written_header_value: bool,
219336d762aSopenharmony_ci    indent: Option<usize>,
220336d762aSopenharmony_ci    buf: &'a mut Formatter,
221336d762aSopenharmony_ci    suffix: &'a str,
222336d762aSopenharmony_ci}
223336d762aSopenharmony_ci
224336d762aSopenharmony_ciimpl<'a> DefaultFormat<'a> {
225336d762aSopenharmony_ci    fn write(mut self, record: &Record) -> io::Result<()> {
226336d762aSopenharmony_ci        self.write_timestamp()?;
227336d762aSopenharmony_ci        self.write_level(record)?;
228336d762aSopenharmony_ci        self.write_module_path(record)?;
229336d762aSopenharmony_ci        self.write_target(record)?;
230336d762aSopenharmony_ci        self.finish_header()?;
231336d762aSopenharmony_ci
232336d762aSopenharmony_ci        self.write_args(record)
233336d762aSopenharmony_ci    }
234336d762aSopenharmony_ci
235336d762aSopenharmony_ci    fn subtle_style(&self, text: &'static str) -> SubtleStyle {
236336d762aSopenharmony_ci        #[cfg(feature = "termcolor")]
237336d762aSopenharmony_ci        {
238336d762aSopenharmony_ci            self.buf
239336d762aSopenharmony_ci                .style()
240336d762aSopenharmony_ci                .set_color(Color::Black)
241336d762aSopenharmony_ci                .set_intense(true)
242336d762aSopenharmony_ci                .clone()
243336d762aSopenharmony_ci                .into_value(text)
244336d762aSopenharmony_ci        }
245336d762aSopenharmony_ci        #[cfg(not(feature = "termcolor"))]
246336d762aSopenharmony_ci        {
247336d762aSopenharmony_ci            text
248336d762aSopenharmony_ci        }
249336d762aSopenharmony_ci    }
250336d762aSopenharmony_ci
251336d762aSopenharmony_ci    fn write_header_value<T>(&mut self, value: T) -> io::Result<()>
252336d762aSopenharmony_ci    where
253336d762aSopenharmony_ci        T: Display,
254336d762aSopenharmony_ci    {
255336d762aSopenharmony_ci        if !self.written_header_value {
256336d762aSopenharmony_ci            self.written_header_value = true;
257336d762aSopenharmony_ci
258336d762aSopenharmony_ci            let open_brace = self.subtle_style("[");
259336d762aSopenharmony_ci            write!(self.buf, "{}{}", open_brace, value)
260336d762aSopenharmony_ci        } else {
261336d762aSopenharmony_ci            write!(self.buf, " {}", value)
262336d762aSopenharmony_ci        }
263336d762aSopenharmony_ci    }
264336d762aSopenharmony_ci
265336d762aSopenharmony_ci    fn write_level(&mut self, record: &Record) -> io::Result<()> {
266336d762aSopenharmony_ci        if !self.level {
267336d762aSopenharmony_ci            return Ok(());
268336d762aSopenharmony_ci        }
269336d762aSopenharmony_ci
270336d762aSopenharmony_ci        let level = {
271336d762aSopenharmony_ci            #[cfg(feature = "termcolor")]
272336d762aSopenharmony_ci            {
273336d762aSopenharmony_ci                self.buf.default_styled_level(record.level())
274336d762aSopenharmony_ci            }
275336d762aSopenharmony_ci            #[cfg(not(feature = "termcolor"))]
276336d762aSopenharmony_ci            {
277336d762aSopenharmony_ci                record.level()
278336d762aSopenharmony_ci            }
279336d762aSopenharmony_ci        };
280336d762aSopenharmony_ci
281336d762aSopenharmony_ci        self.write_header_value(format_args!("{:<5}", level))
282336d762aSopenharmony_ci    }
283336d762aSopenharmony_ci
284336d762aSopenharmony_ci    fn write_timestamp(&mut self) -> io::Result<()> {
285336d762aSopenharmony_ci        #[cfg(feature = "humantime")]
286336d762aSopenharmony_ci        {
287336d762aSopenharmony_ci            use self::TimestampPrecision::*;
288336d762aSopenharmony_ci            let ts = match self.timestamp {
289336d762aSopenharmony_ci                None => return Ok(()),
290336d762aSopenharmony_ci                Some(Seconds) => self.buf.timestamp_seconds(),
291336d762aSopenharmony_ci                Some(Millis) => self.buf.timestamp_millis(),
292336d762aSopenharmony_ci                Some(Micros) => self.buf.timestamp_micros(),
293336d762aSopenharmony_ci                Some(Nanos) => self.buf.timestamp_nanos(),
294336d762aSopenharmony_ci            };
295336d762aSopenharmony_ci
296336d762aSopenharmony_ci            self.write_header_value(ts)
297336d762aSopenharmony_ci        }
298336d762aSopenharmony_ci        #[cfg(not(feature = "humantime"))]
299336d762aSopenharmony_ci        {
300336d762aSopenharmony_ci            // Trick the compiler to think we have used self.timestamp
301336d762aSopenharmony_ci            // Workaround for "field is never used: `timestamp`" compiler nag.
302336d762aSopenharmony_ci            let _ = self.timestamp;
303336d762aSopenharmony_ci            Ok(())
304336d762aSopenharmony_ci        }
305336d762aSopenharmony_ci    }
306336d762aSopenharmony_ci
307336d762aSopenharmony_ci    fn write_module_path(&mut self, record: &Record) -> io::Result<()> {
308336d762aSopenharmony_ci        if !self.module_path {
309336d762aSopenharmony_ci            return Ok(());
310336d762aSopenharmony_ci        }
311336d762aSopenharmony_ci
312336d762aSopenharmony_ci        if let Some(module_path) = record.module_path() {
313336d762aSopenharmony_ci            self.write_header_value(module_path)
314336d762aSopenharmony_ci        } else {
315336d762aSopenharmony_ci            Ok(())
316336d762aSopenharmony_ci        }
317336d762aSopenharmony_ci    }
318336d762aSopenharmony_ci
319336d762aSopenharmony_ci    fn write_target(&mut self, record: &Record) -> io::Result<()> {
320336d762aSopenharmony_ci        if !self.target {
321336d762aSopenharmony_ci            return Ok(());
322336d762aSopenharmony_ci        }
323336d762aSopenharmony_ci
324336d762aSopenharmony_ci        match record.target() {
325336d762aSopenharmony_ci            "" => Ok(()),
326336d762aSopenharmony_ci            target => self.write_header_value(target),
327336d762aSopenharmony_ci        }
328336d762aSopenharmony_ci    }
329336d762aSopenharmony_ci
330336d762aSopenharmony_ci    fn finish_header(&mut self) -> io::Result<()> {
331336d762aSopenharmony_ci        if self.written_header_value {
332336d762aSopenharmony_ci            let close_brace = self.subtle_style("]");
333336d762aSopenharmony_ci            write!(self.buf, "{} ", close_brace)
334336d762aSopenharmony_ci        } else {
335336d762aSopenharmony_ci            Ok(())
336336d762aSopenharmony_ci        }
337336d762aSopenharmony_ci    }
338336d762aSopenharmony_ci
339336d762aSopenharmony_ci    fn write_args(&mut self, record: &Record) -> io::Result<()> {
340336d762aSopenharmony_ci        match self.indent {
341336d762aSopenharmony_ci            // Fast path for no indentation
342336d762aSopenharmony_ci            None => write!(self.buf, "{}{}", record.args(), self.suffix),
343336d762aSopenharmony_ci
344336d762aSopenharmony_ci            Some(indent_count) => {
345336d762aSopenharmony_ci                // Create a wrapper around the buffer only if we have to actually indent the message
346336d762aSopenharmony_ci
347336d762aSopenharmony_ci                struct IndentWrapper<'a, 'b: 'a> {
348336d762aSopenharmony_ci                    fmt: &'a mut DefaultFormat<'b>,
349336d762aSopenharmony_ci                    indent_count: usize,
350336d762aSopenharmony_ci                }
351336d762aSopenharmony_ci
352336d762aSopenharmony_ci                impl<'a, 'b> Write for IndentWrapper<'a, 'b> {
353336d762aSopenharmony_ci                    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
354336d762aSopenharmony_ci                        let mut first = true;
355336d762aSopenharmony_ci                        for chunk in buf.split(|&x| x == b'\n') {
356336d762aSopenharmony_ci                            if !first {
357336d762aSopenharmony_ci                                write!(
358336d762aSopenharmony_ci                                    self.fmt.buf,
359336d762aSopenharmony_ci                                    "{}{:width$}",
360336d762aSopenharmony_ci                                    self.fmt.suffix,
361336d762aSopenharmony_ci                                    "",
362336d762aSopenharmony_ci                                    width = self.indent_count
363336d762aSopenharmony_ci                                )?;
364336d762aSopenharmony_ci                            }
365336d762aSopenharmony_ci                            self.fmt.buf.write_all(chunk)?;
366336d762aSopenharmony_ci                            first = false;
367336d762aSopenharmony_ci                        }
368336d762aSopenharmony_ci
369336d762aSopenharmony_ci                        Ok(buf.len())
370336d762aSopenharmony_ci                    }
371336d762aSopenharmony_ci
372336d762aSopenharmony_ci                    fn flush(&mut self) -> io::Result<()> {
373336d762aSopenharmony_ci                        self.fmt.buf.flush()
374336d762aSopenharmony_ci                    }
375336d762aSopenharmony_ci                }
376336d762aSopenharmony_ci
377336d762aSopenharmony_ci                // The explicit scope here is just to make older versions of Rust happy
378336d762aSopenharmony_ci                {
379336d762aSopenharmony_ci                    let mut wrapper = IndentWrapper {
380336d762aSopenharmony_ci                        fmt: self,
381336d762aSopenharmony_ci                        indent_count,
382336d762aSopenharmony_ci                    };
383336d762aSopenharmony_ci                    write!(wrapper, "{}", record.args())?;
384336d762aSopenharmony_ci                }
385336d762aSopenharmony_ci
386336d762aSopenharmony_ci                write!(self.buf, "{}", self.suffix)?;
387336d762aSopenharmony_ci
388336d762aSopenharmony_ci                Ok(())
389336d762aSopenharmony_ci            }
390336d762aSopenharmony_ci        }
391336d762aSopenharmony_ci    }
392336d762aSopenharmony_ci}
393336d762aSopenharmony_ci
394336d762aSopenharmony_ci#[cfg(test)]
395336d762aSopenharmony_cimod tests {
396336d762aSopenharmony_ci    use super::*;
397336d762aSopenharmony_ci
398336d762aSopenharmony_ci    use log::{Level, Record};
399336d762aSopenharmony_ci
400336d762aSopenharmony_ci    fn write_record(record: Record, fmt: DefaultFormat) -> String {
401336d762aSopenharmony_ci        let buf = fmt.buf.buf.clone();
402336d762aSopenharmony_ci
403336d762aSopenharmony_ci        fmt.write(&record).expect("failed to write record");
404336d762aSopenharmony_ci
405336d762aSopenharmony_ci        let buf = buf.borrow();
406336d762aSopenharmony_ci        String::from_utf8(buf.bytes().to_vec()).expect("failed to read record")
407336d762aSopenharmony_ci    }
408336d762aSopenharmony_ci
409336d762aSopenharmony_ci    fn write_target(target: &str, fmt: DefaultFormat) -> String {
410336d762aSopenharmony_ci        write_record(
411336d762aSopenharmony_ci            Record::builder()
412336d762aSopenharmony_ci                .args(format_args!("log\nmessage"))
413336d762aSopenharmony_ci                .level(Level::Info)
414336d762aSopenharmony_ci                .file(Some("test.rs"))
415336d762aSopenharmony_ci                .line(Some(144))
416336d762aSopenharmony_ci                .module_path(Some("test::path"))
417336d762aSopenharmony_ci                .target(target)
418336d762aSopenharmony_ci                .build(),
419336d762aSopenharmony_ci            fmt,
420336d762aSopenharmony_ci        )
421336d762aSopenharmony_ci    }
422336d762aSopenharmony_ci
423336d762aSopenharmony_ci    fn write(fmt: DefaultFormat) -> String {
424336d762aSopenharmony_ci        write_target("", fmt)
425336d762aSopenharmony_ci    }
426336d762aSopenharmony_ci
427336d762aSopenharmony_ci    #[test]
428336d762aSopenharmony_ci    fn format_with_header() {
429336d762aSopenharmony_ci        let writer = writer::Builder::new()
430336d762aSopenharmony_ci            .write_style(WriteStyle::Never)
431336d762aSopenharmony_ci            .build();
432336d762aSopenharmony_ci
433336d762aSopenharmony_ci        let mut f = Formatter::new(&writer);
434336d762aSopenharmony_ci
435336d762aSopenharmony_ci        let written = write(DefaultFormat {
436336d762aSopenharmony_ci            timestamp: None,
437336d762aSopenharmony_ci            module_path: true,
438336d762aSopenharmony_ci            target: false,
439336d762aSopenharmony_ci            level: true,
440336d762aSopenharmony_ci            written_header_value: false,
441336d762aSopenharmony_ci            indent: None,
442336d762aSopenharmony_ci            suffix: "\n",
443336d762aSopenharmony_ci            buf: &mut f,
444336d762aSopenharmony_ci        });
445336d762aSopenharmony_ci
446336d762aSopenharmony_ci        assert_eq!("[INFO  test::path] log\nmessage\n", written);
447336d762aSopenharmony_ci    }
448336d762aSopenharmony_ci
449336d762aSopenharmony_ci    #[test]
450336d762aSopenharmony_ci    fn format_no_header() {
451336d762aSopenharmony_ci        let writer = writer::Builder::new()
452336d762aSopenharmony_ci            .write_style(WriteStyle::Never)
453336d762aSopenharmony_ci            .build();
454336d762aSopenharmony_ci
455336d762aSopenharmony_ci        let mut f = Formatter::new(&writer);
456336d762aSopenharmony_ci
457336d762aSopenharmony_ci        let written = write(DefaultFormat {
458336d762aSopenharmony_ci            timestamp: None,
459336d762aSopenharmony_ci            module_path: false,
460336d762aSopenharmony_ci            target: false,
461336d762aSopenharmony_ci            level: false,
462336d762aSopenharmony_ci            written_header_value: false,
463336d762aSopenharmony_ci            indent: None,
464336d762aSopenharmony_ci            suffix: "\n",
465336d762aSopenharmony_ci            buf: &mut f,
466336d762aSopenharmony_ci        });
467336d762aSopenharmony_ci
468336d762aSopenharmony_ci        assert_eq!("log\nmessage\n", written);
469336d762aSopenharmony_ci    }
470336d762aSopenharmony_ci
471336d762aSopenharmony_ci    #[test]
472336d762aSopenharmony_ci    fn format_indent_spaces() {
473336d762aSopenharmony_ci        let writer = writer::Builder::new()
474336d762aSopenharmony_ci            .write_style(WriteStyle::Never)
475336d762aSopenharmony_ci            .build();
476336d762aSopenharmony_ci
477336d762aSopenharmony_ci        let mut f = Formatter::new(&writer);
478336d762aSopenharmony_ci
479336d762aSopenharmony_ci        let written = write(DefaultFormat {
480336d762aSopenharmony_ci            timestamp: None,
481336d762aSopenharmony_ci            module_path: true,
482336d762aSopenharmony_ci            target: false,
483336d762aSopenharmony_ci            level: true,
484336d762aSopenharmony_ci            written_header_value: false,
485336d762aSopenharmony_ci            indent: Some(4),
486336d762aSopenharmony_ci            suffix: "\n",
487336d762aSopenharmony_ci            buf: &mut f,
488336d762aSopenharmony_ci        });
489336d762aSopenharmony_ci
490336d762aSopenharmony_ci        assert_eq!("[INFO  test::path] log\n    message\n", written);
491336d762aSopenharmony_ci    }
492336d762aSopenharmony_ci
493336d762aSopenharmony_ci    #[test]
494336d762aSopenharmony_ci    fn format_indent_zero_spaces() {
495336d762aSopenharmony_ci        let writer = writer::Builder::new()
496336d762aSopenharmony_ci            .write_style(WriteStyle::Never)
497336d762aSopenharmony_ci            .build();
498336d762aSopenharmony_ci
499336d762aSopenharmony_ci        let mut f = Formatter::new(&writer);
500336d762aSopenharmony_ci
501336d762aSopenharmony_ci        let written = write(DefaultFormat {
502336d762aSopenharmony_ci            timestamp: None,
503336d762aSopenharmony_ci            module_path: true,
504336d762aSopenharmony_ci            target: false,
505336d762aSopenharmony_ci            level: true,
506336d762aSopenharmony_ci            written_header_value: false,
507336d762aSopenharmony_ci            indent: Some(0),
508336d762aSopenharmony_ci            suffix: "\n",
509336d762aSopenharmony_ci            buf: &mut f,
510336d762aSopenharmony_ci        });
511336d762aSopenharmony_ci
512336d762aSopenharmony_ci        assert_eq!("[INFO  test::path] log\nmessage\n", written);
513336d762aSopenharmony_ci    }
514336d762aSopenharmony_ci
515336d762aSopenharmony_ci    #[test]
516336d762aSopenharmony_ci    fn format_indent_spaces_no_header() {
517336d762aSopenharmony_ci        let writer = writer::Builder::new()
518336d762aSopenharmony_ci            .write_style(WriteStyle::Never)
519336d762aSopenharmony_ci            .build();
520336d762aSopenharmony_ci
521336d762aSopenharmony_ci        let mut f = Formatter::new(&writer);
522336d762aSopenharmony_ci
523336d762aSopenharmony_ci        let written = write(DefaultFormat {
524336d762aSopenharmony_ci            timestamp: None,
525336d762aSopenharmony_ci            module_path: false,
526336d762aSopenharmony_ci            target: false,
527336d762aSopenharmony_ci            level: false,
528336d762aSopenharmony_ci            written_header_value: false,
529336d762aSopenharmony_ci            indent: Some(4),
530336d762aSopenharmony_ci            suffix: "\n",
531336d762aSopenharmony_ci            buf: &mut f,
532336d762aSopenharmony_ci        });
533336d762aSopenharmony_ci
534336d762aSopenharmony_ci        assert_eq!("log\n    message\n", written);
535336d762aSopenharmony_ci    }
536336d762aSopenharmony_ci
537336d762aSopenharmony_ci    #[test]
538336d762aSopenharmony_ci    fn format_suffix() {
539336d762aSopenharmony_ci        let writer = writer::Builder::new()
540336d762aSopenharmony_ci            .write_style(WriteStyle::Never)
541336d762aSopenharmony_ci            .build();
542336d762aSopenharmony_ci
543336d762aSopenharmony_ci        let mut f = Formatter::new(&writer);
544336d762aSopenharmony_ci
545336d762aSopenharmony_ci        let written = write(DefaultFormat {
546336d762aSopenharmony_ci            timestamp: None,
547336d762aSopenharmony_ci            module_path: false,
548336d762aSopenharmony_ci            target: false,
549336d762aSopenharmony_ci            level: false,
550336d762aSopenharmony_ci            written_header_value: false,
551336d762aSopenharmony_ci            indent: None,
552336d762aSopenharmony_ci            suffix: "\n\n",
553336d762aSopenharmony_ci            buf: &mut f,
554336d762aSopenharmony_ci        });
555336d762aSopenharmony_ci
556336d762aSopenharmony_ci        assert_eq!("log\nmessage\n\n", written);
557336d762aSopenharmony_ci    }
558336d762aSopenharmony_ci
559336d762aSopenharmony_ci    #[test]
560336d762aSopenharmony_ci    fn format_suffix_with_indent() {
561336d762aSopenharmony_ci        let writer = writer::Builder::new()
562336d762aSopenharmony_ci            .write_style(WriteStyle::Never)
563336d762aSopenharmony_ci            .build();
564336d762aSopenharmony_ci
565336d762aSopenharmony_ci        let mut f = Formatter::new(&writer);
566336d762aSopenharmony_ci
567336d762aSopenharmony_ci        let written = write(DefaultFormat {
568336d762aSopenharmony_ci            timestamp: None,
569336d762aSopenharmony_ci            module_path: false,
570336d762aSopenharmony_ci            target: false,
571336d762aSopenharmony_ci            level: false,
572336d762aSopenharmony_ci            written_header_value: false,
573336d762aSopenharmony_ci            indent: Some(4),
574336d762aSopenharmony_ci            suffix: "\n\n",
575336d762aSopenharmony_ci            buf: &mut f,
576336d762aSopenharmony_ci        });
577336d762aSopenharmony_ci
578336d762aSopenharmony_ci        assert_eq!("log\n\n    message\n\n", written);
579336d762aSopenharmony_ci    }
580336d762aSopenharmony_ci
581336d762aSopenharmony_ci    #[test]
582336d762aSopenharmony_ci    fn format_target() {
583336d762aSopenharmony_ci        let writer = writer::Builder::new()
584336d762aSopenharmony_ci            .write_style(WriteStyle::Never)
585336d762aSopenharmony_ci            .build();
586336d762aSopenharmony_ci
587336d762aSopenharmony_ci        let mut f = Formatter::new(&writer);
588336d762aSopenharmony_ci
589336d762aSopenharmony_ci        let written = write_target(
590336d762aSopenharmony_ci            "target",
591336d762aSopenharmony_ci            DefaultFormat {
592336d762aSopenharmony_ci                timestamp: None,
593336d762aSopenharmony_ci                module_path: true,
594336d762aSopenharmony_ci                target: true,
595336d762aSopenharmony_ci                level: true,
596336d762aSopenharmony_ci                written_header_value: false,
597336d762aSopenharmony_ci                indent: None,
598336d762aSopenharmony_ci                suffix: "\n",
599336d762aSopenharmony_ci                buf: &mut f,
600336d762aSopenharmony_ci            },
601336d762aSopenharmony_ci        );
602336d762aSopenharmony_ci
603336d762aSopenharmony_ci        assert_eq!("[INFO  test::path target] log\nmessage\n", written);
604336d762aSopenharmony_ci    }
605336d762aSopenharmony_ci
606336d762aSopenharmony_ci    #[test]
607336d762aSopenharmony_ci    fn format_empty_target() {
608336d762aSopenharmony_ci        let writer = writer::Builder::new()
609336d762aSopenharmony_ci            .write_style(WriteStyle::Never)
610336d762aSopenharmony_ci            .build();
611336d762aSopenharmony_ci
612336d762aSopenharmony_ci        let mut f = Formatter::new(&writer);
613336d762aSopenharmony_ci
614336d762aSopenharmony_ci        let written = write(DefaultFormat {
615336d762aSopenharmony_ci            timestamp: None,
616336d762aSopenharmony_ci            module_path: true,
617336d762aSopenharmony_ci            target: true,
618336d762aSopenharmony_ci            level: true,
619336d762aSopenharmony_ci            written_header_value: false,
620336d762aSopenharmony_ci            indent: None,
621336d762aSopenharmony_ci            suffix: "\n",
622336d762aSopenharmony_ci            buf: &mut f,
623336d762aSopenharmony_ci        });
624336d762aSopenharmony_ci
625336d762aSopenharmony_ci        assert_eq!("[INFO  test::path] log\nmessage\n", written);
626336d762aSopenharmony_ci    }
627336d762aSopenharmony_ci
628336d762aSopenharmony_ci    #[test]
629336d762aSopenharmony_ci    fn format_no_target() {
630336d762aSopenharmony_ci        let writer = writer::Builder::new()
631336d762aSopenharmony_ci            .write_style(WriteStyle::Never)
632336d762aSopenharmony_ci            .build();
633336d762aSopenharmony_ci
634336d762aSopenharmony_ci        let mut f = Formatter::new(&writer);
635336d762aSopenharmony_ci
636336d762aSopenharmony_ci        let written = write_target(
637336d762aSopenharmony_ci            "target",
638336d762aSopenharmony_ci            DefaultFormat {
639336d762aSopenharmony_ci                timestamp: None,
640336d762aSopenharmony_ci                module_path: true,
641336d762aSopenharmony_ci                target: false,
642336d762aSopenharmony_ci                level: true,
643336d762aSopenharmony_ci                written_header_value: false,
644336d762aSopenharmony_ci                indent: None,
645336d762aSopenharmony_ci                suffix: "\n",
646336d762aSopenharmony_ci                buf: &mut f,
647336d762aSopenharmony_ci            },
648336d762aSopenharmony_ci        );
649336d762aSopenharmony_ci
650336d762aSopenharmony_ci        assert_eq!("[INFO  test::path] log\nmessage\n", written);
651336d762aSopenharmony_ci    }
652336d762aSopenharmony_ci}
653