logforth_core/layout/
plain_text.rs

1// Copyright 2024 FastLabs Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt::Write;
16use std::time::SystemTime;
17
18use crate::Diagnostic;
19use crate::Error;
20use crate::Layout;
21use crate::kv::Key;
22use crate::kv::Value;
23use crate::kv::Visitor;
24use crate::record::Record;
25
26/// A layout that formats log record as plain text.
27///
28/// Output format:
29///
30/// ```text
31/// 2024-08-11T22:44:57.172105+08:00 ERROR file: examples/file.rs:51 Hello error!
32/// 2024-08-11T22:44:57.172219+08:00  WARN file: examples/file.rs:52 Hello warn!
33/// 2024-08-11T22:44:57.172276+08:00  INFO file: examples/file.rs:53 Hello info!
34/// 2024-08-11T22:44:57.172329+08:00 DEBUG file: examples/file.rs:54 Hello debug!
35/// 2024-08-11T22:44:57.172382+08:00 TRACE file: examples/file.rs:55 Hello trace!
36/// ```
37///
38/// # Examples
39///
40/// ```
41/// use logforth_core::layout::PlainTextLayout;
42///
43/// let text_layout = PlainTextLayout::default();
44/// ```
45
46#[derive(Debug, Clone, Default)]
47#[non_exhaustive]
48pub struct PlainTextLayout {}
49
50struct KvWriter {
51    text: String,
52}
53
54impl Visitor for KvWriter {
55    fn visit(&mut self, key: Key, value: Value) -> Result<(), Error> {
56        // SAFETY: write to a string always succeeds
57        write!(&mut self.text, " {key}={value}").unwrap();
58        Ok(())
59    }
60}
61
62impl Layout for PlainTextLayout {
63    fn format(&self, record: &Record, diags: &[Box<dyn Diagnostic>]) -> Result<Vec<u8>, Error> {
64        let mut text = String::new();
65
66        let time = record.time();
67        match time.duration_since(SystemTime::UNIX_EPOCH) {
68            Ok(dur) => {
69                let time = dur.as_nanos();
70                write!(&mut text, "{time}").unwrap();
71            }
72            Err(err) => {
73                let time = err.duration().as_nanos();
74                write!(&mut text, "-{time}").unwrap();
75            }
76        }
77
78        let level = record.level().as_str();
79        let target = record.target();
80        let file = record.filename();
81        let line = record.line().unwrap_or_default();
82        let message = record.payload();
83        write!(&mut text, " {level:>5} {target}: {file}:{line} {message}").unwrap();
84
85        let mut visitor = KvWriter { text };
86        record.key_values().visit(&mut visitor)?;
87        for d in diags {
88            d.visit(&mut visitor)?;
89        }
90
91        Ok(visitor.text.into_bytes())
92    }
93}