1use std::cell::RefCell;
33use std::fmt::Display;
34use std::io::prelude::*;
35use std::rc::Rc;
36use std::{fmt, io, mem};
37
38use log::Record;
39
40mod humantime;
41pub(crate) mod writer;
42
43pub use self::humantime::glob::*;
44pub use self::writer::glob::*;
45
46use self::writer::{Buffer, Writer};
47
48pub(crate) mod glob {
49    pub use super::{Target, TimestampPrecision, WriteStyle};
50}
51
52#[derive(Copy, Clone, Debug)]
58pub enum TimestampPrecision {
59    Seconds,
61    Millis,
63    Micros,
65    Nanos,
67}
68
69impl Default for TimestampPrecision {
71    fn default() -> Self {
72        TimestampPrecision::Seconds
73    }
74}
75
76pub struct Formatter {
98    buf: Rc<RefCell<Buffer>>,
99    write_style: WriteStyle,
100}
101
102impl Formatter {
103    pub(crate) fn new(writer: &Writer) -> Self {
104        Formatter {
105            buf: Rc::new(RefCell::new(writer.buffer())),
106            write_style: writer.write_style(),
107        }
108    }
109
110    pub(crate) fn write_style(&self) -> WriteStyle {
111        self.write_style
112    }
113
114    pub(crate) fn print(&self, writer: &Writer) -> io::Result<()> {
115        writer.print(&self.buf.borrow())
116    }
117
118    pub(crate) fn clear(&mut self) {
119        self.buf.borrow_mut().clear()
120    }
121}
122
123impl Write for Formatter {
124    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
125        self.buf.borrow_mut().write(buf)
126    }
127
128    fn flush(&mut self) -> io::Result<()> {
129        self.buf.borrow_mut().flush()
130    }
131}
132
133impl fmt::Debug for Formatter {
134    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135        f.debug_struct("Formatter").finish()
136    }
137}
138
139pub(crate) type FormatFn = Box<dyn Fn(&mut Formatter, &Record) -> io::Result<()> + Sync + Send>;
140
141pub(crate) struct Builder {
142    pub format_timestamp: Option<TimestampPrecision>,
143    pub format_module_path: bool,
144    pub format_level: bool,
145    pub format_indent: Option<usize>,
146    pub custom_format: Option<FormatFn>,
147    pub format_suffix: &'static str,
148    built: bool,
149}
150
151impl Default for Builder {
152    fn default() -> Self {
153        Builder {
154            format_timestamp: Some(Default::default()),
155            format_module_path: true,
156            format_level: true,
157            format_indent: Some(4),
158            custom_format: None,
159            format_suffix: "\n",
160            built: false,
161        }
162    }
163}
164
165impl Builder {
166    pub fn build(&mut self) -> FormatFn {
172        assert!(!self.built, "attempt to re-use consumed builder");
173
174        let built = mem::replace(
175            self,
176            Builder {
177                built: true,
178                ..Default::default()
179            },
180        );
181
182        if let Some(fmt) = built.custom_format {
183            fmt
184        } else {
185            Box::new(move |buf, record| {
186                let fmt = DefaultFormat {
187                    timestamp: built.format_timestamp,
188                    module_path: built.format_module_path,
189                    level: built.format_level,
190                    written_header_value: false,
191                    indent: built.format_indent,
192                    suffix: built.format_suffix,
193                    buf,
194                };
195
196                fmt.write(record)
197            })
198        }
199    }
200}
201
202#[cfg(feature = "termcolor")]
203type SubtleStyle = StyledValue<'static, &'static str>;
204#[cfg(not(feature = "termcolor"))]
205type SubtleStyle = &'static str;
206
207struct DefaultFormat<'a> {
211    timestamp: Option<TimestampPrecision>,
212    module_path: bool,
213    level: bool,
214    written_header_value: bool,
215    indent: Option<usize>,
216    buf: &'a mut Formatter,
217    suffix: &'a str,
218}
219
220impl<'a> DefaultFormat<'a> {
221    fn write(mut self, record: &Record) -> io::Result<()> {
222        self.write_timestamp()?;
223        self.write_level(record)?;
224        self.write_module_path(record)?;
225        self.finish_header()?;
226
227        self.write_args(record)
228    }
229
230    fn subtle_style(&self, text: &'static str) -> SubtleStyle {
231        #[cfg(feature = "termcolor")]
232        {
233            self.buf
234                .style()
235                .set_color(Color::Black)
236                .set_intense(true)
237                .clone()
238                .into_value(text)
239        }
240        #[cfg(not(feature = "termcolor"))]
241        {
242            text
243        }
244    }
245
246    fn write_header_value<T>(&mut self, value: T) -> io::Result<()>
247    where
248        T: Display,
249    {
250        if !self.written_header_value {
251            self.written_header_value = true;
252
253            let open_brace = self.subtle_style("[");
254            write!(self.buf, "{}{}", open_brace, value)
255        } else {
256            write!(self.buf, " {}", value)
257        }
258    }
259
260    fn write_level(&mut self, record: &Record) -> io::Result<()> {
261        if !self.level {
262            return Ok(());
263        }
264
265        let level = {
266            #[cfg(feature = "termcolor")]
267            {
268                self.buf.default_styled_level(record.level())
269            }
270            #[cfg(not(feature = "termcolor"))]
271            {
272                record.level()
273            }
274        };
275
276        self.write_header_value(format_args!("{:<5}", level))
277    }
278
279    fn write_timestamp(&mut self) -> io::Result<()> {
280        #[cfg(feature = "humantime")]
281        {
282            use self::TimestampPrecision::*;
283            let ts = match self.timestamp {
284                None => return Ok(()),
285                Some(Seconds) => self.buf.timestamp_seconds(),
286                Some(Millis) => self.buf.timestamp_millis(),
287                Some(Micros) => self.buf.timestamp_micros(),
288                Some(Nanos) => self.buf.timestamp_nanos(),
289            };
290
291            self.write_header_value(ts)
292        }
293        #[cfg(not(feature = "humantime"))]
294        {
295            let _ = self.timestamp;
298            Ok(())
299        }
300    }
301
302    fn write_module_path(&mut self, record: &Record) -> io::Result<()> {
303        if !self.module_path {
304            return Ok(());
305        }
306
307        if let Some(module_path) = record.module_path() {
308            self.write_header_value(module_path)
309        } else {
310            Ok(())
311        }
312    }
313
314    fn finish_header(&mut self) -> io::Result<()> {
315        if self.written_header_value {
316            let close_brace = self.subtle_style("]");
317            write!(self.buf, "{} ", close_brace)
318        } else {
319            Ok(())
320        }
321    }
322
323    fn write_args(&mut self, record: &Record) -> io::Result<()> {
324        match self.indent {
325            None => write!(self.buf, "{}{}", record.args(), self.suffix),
327
328            Some(indent_count) => {
329                struct IndentWrapper<'a, 'b: 'a> {
332                    fmt: &'a mut DefaultFormat<'b>,
333                    indent_count: usize,
334                }
335
336                impl<'a, 'b> Write for IndentWrapper<'a, 'b> {
337                    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
338                        let mut first = true;
339                        for chunk in buf.split(|&x| x == b'\n') {
340                            if !first {
341                                write!(
342                                    self.fmt.buf,
343                                    "{}{:width$}",
344                                    self.fmt.suffix,
345                                    "",
346                                    width = self.indent_count
347                                )?;
348                            }
349                            self.fmt.buf.write_all(chunk)?;
350                            first = false;
351                        }
352
353                        Ok(buf.len())
354                    }
355
356                    fn flush(&mut self) -> io::Result<()> {
357                        self.fmt.buf.flush()
358                    }
359                }
360
361                {
363                    let mut wrapper = IndentWrapper {
364                        fmt: self,
365                        indent_count,
366                    };
367                    write!(wrapper, "{}", record.args())?;
368                }
369
370                write!(self.buf, "{}", self.suffix)?;
371
372                Ok(())
373            }
374        }
375    }
376}
377
378#[cfg(test)]
379mod tests {
380    use super::*;
381
382    use log::{Level, Record};
383
384    fn write(fmt: DefaultFormat) -> String {
385        let buf = fmt.buf.buf.clone();
386
387        let record = Record::builder()
388            .args(format_args!("log\nmessage"))
389            .level(Level::Info)
390            .file(Some("test.rs"))
391            .line(Some(144))
392            .module_path(Some("test::path"))
393            .build();
394
395        fmt.write(&record).expect("failed to write record");
396
397        let buf = buf.borrow();
398        String::from_utf8(buf.bytes().to_vec()).expect("failed to read record")
399    }
400
401    #[test]
402    fn format_with_header() {
403        let writer = writer::Builder::new()
404            .write_style(WriteStyle::Never)
405            .build();
406
407        let mut f = Formatter::new(&writer);
408
409        let written = write(DefaultFormat {
410            timestamp: None,
411            module_path: true,
412            level: true,
413            written_header_value: false,
414            indent: None,
415            suffix: "\n",
416            buf: &mut f,
417        });
418
419        assert_eq!("[INFO  test::path] log\nmessage\n", written);
420    }
421
422    #[test]
423    fn format_no_header() {
424        let writer = writer::Builder::new()
425            .write_style(WriteStyle::Never)
426            .build();
427
428        let mut f = Formatter::new(&writer);
429
430        let written = write(DefaultFormat {
431            timestamp: None,
432            module_path: false,
433            level: false,
434            written_header_value: false,
435            indent: None,
436            suffix: "\n",
437            buf: &mut f,
438        });
439
440        assert_eq!("log\nmessage\n", written);
441    }
442
443    #[test]
444    fn format_indent_spaces() {
445        let writer = writer::Builder::new()
446            .write_style(WriteStyle::Never)
447            .build();
448
449        let mut f = Formatter::new(&writer);
450
451        let written = write(DefaultFormat {
452            timestamp: None,
453            module_path: true,
454            level: true,
455            written_header_value: false,
456            indent: Some(4),
457            suffix: "\n",
458            buf: &mut f,
459        });
460
461        assert_eq!("[INFO  test::path] log\n    message\n", written);
462    }
463
464    #[test]
465    fn format_indent_zero_spaces() {
466        let writer = writer::Builder::new()
467            .write_style(WriteStyle::Never)
468            .build();
469
470        let mut f = Formatter::new(&writer);
471
472        let written = write(DefaultFormat {
473            timestamp: None,
474            module_path: true,
475            level: true,
476            written_header_value: false,
477            indent: Some(0),
478            suffix: "\n",
479            buf: &mut f,
480        });
481
482        assert_eq!("[INFO  test::path] log\nmessage\n", written);
483    }
484
485    #[test]
486    fn format_indent_spaces_no_header() {
487        let writer = writer::Builder::new()
488            .write_style(WriteStyle::Never)
489            .build();
490
491        let mut f = Formatter::new(&writer);
492
493        let written = write(DefaultFormat {
494            timestamp: None,
495            module_path: false,
496            level: false,
497            written_header_value: false,
498            indent: Some(4),
499            suffix: "\n",
500            buf: &mut f,
501        });
502
503        assert_eq!("log\n    message\n", written);
504    }
505
506    #[test]
507    fn format_suffix() {
508        let writer = writer::Builder::new()
509            .write_style(WriteStyle::Never)
510            .build();
511
512        let mut f = Formatter::new(&writer);
513
514        let written = write(DefaultFormat {
515            timestamp: None,
516            module_path: false,
517            level: false,
518            written_header_value: false,
519            indent: None,
520            suffix: "\n\n",
521            buf: &mut f,
522        });
523
524        assert_eq!("log\nmessage\n\n", written);
525    }
526
527    #[test]
528    fn format_suffix_with_indent() {
529        let writer = writer::Builder::new()
530            .write_style(WriteStyle::Never)
531            .build();
532
533        let mut f = Formatter::new(&writer);
534
535        let written = write(DefaultFormat {
536            timestamp: None,
537            module_path: false,
538            level: false,
539            written_header_value: false,
540            indent: Some(4),
541            suffix: "\n\n",
542            buf: &mut f,
543        });
544
545        assert_eq!("log\n\n    message\n\n", written);
546    }
547}