custom_format/
custom-format.rs

1use std::fmt::Display;
2
3use ftlog::{
4    appender::{file::Period, FileAppender},
5    info, FtLogFormat, LoggerGuard,
6};
7use log::{Level, LevelFilter, Record};
8use time::Duration;
9fn init() -> LoggerGuard {
10    // Custom log style.
11
12    // A formatter defines how to build a message.
13    // Since Formatting message into string can slow down the log macro call,
14    // the idomatic way is to send required field as is to log thread, and build
15    // message in log thread.
16    struct MyFormatter;
17    impl FtLogFormat for MyFormatter {
18        fn msg(&self, record: &Record) -> Box<dyn Send + Sync + std::fmt::Display> {
19            Box::new(Msg {
20                level: record.level(),
21                thread: std::thread::current().name().map(|n| n.to_string()),
22                file: record.file_static(),
23                line: record.line(),
24                args: format!("{}", record.args()),
25                module_path: record.module_path_static(),
26            })
27        }
28    }
29
30    // Store necessary field, define how to build into string with `Display` trait.
31    struct Msg {
32        level: Level,
33        thread: Option<String>,
34        file: Option<&'static str>,
35        line: Option<u32>,
36        args: String,
37        module_path: Option<&'static str>,
38    }
39
40    impl Display for Msg {
41        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42            f.write_str(&format!(
43                "{}@{}||{}:{}[{}] {}",
44                self.thread.as_ref().map(|x| x.as_str()).unwrap_or(""),
45                self.module_path.unwrap_or(""),
46                self.file.unwrap_or(""),
47                self.line.unwrap_or(0),
48                self.level,
49                self.args
50            ))
51        }
52    }
53
54    let time_format = time::format_description::parse_owned::<1>(
55        "[year]/[month]/[day] [hour]:[minute]:[second].[subsecond digits:6]",
56    )
57    .unwrap();
58    ftlog::Builder::new()
59        // use our own format
60        .format(MyFormatter)
61        // use our own time format
62        .time_format(time_format)
63        // global max log level
64        .max_log_level(LevelFilter::Info)
65        // define root appender, pass None would write to stderr
66        .root(
67            FileAppender::builder()
68                .path("./current.log")
69                .rotate(Period::Day)
70                .expire(Duration::days(7))
71                .build(),
72        )
73        // ---------- configure additional filter ----------
74        // write to "ftlog-appender" appender, with different level filter
75        .filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
76        // write to root appender, but with different level filter
77        .filter("ftlog", None, LevelFilter::Trace)
78        // write to "ftlog" appender, with default level filter
79        .filter("ftlog::appender::file", "ftlog", None)
80        // ----------  configure additional appender ----------
81        // new appender
82        .appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
83        // new appender, rotate to new file every Day
84        .appender("ftlog", FileAppender::rotate("ftlog.log", Period::Day))
85        .try_init()
86        .expect("logger build or set failed")
87}
88
89fn main() {
90    let _guard = init();
91    info!("Hello, world!");
92    for i in 0..120 {
93        info!("running {}!", i);
94        info!(limit=3000i64; "limit running{} !", i);
95        std::thread::sleep(std::time::Duration::from_secs(1));
96    }
97}
98
99/*
100Output:
101
1022022/11/11 13:53:13.933123 0ms logger@ftlog||src/lib.rs:439[WARN] Logs with level more verbose than INFO will be ignored in `ftlog`
1032022/11/11 13:53:13.933123 0ms main@complex||examples/complex.rs:83[INFO] Hello, world!
1042022/11/11 13:53:13.934123 1ms main@complex||examples/complex.rs:85[INFO] running 0!
1052022/11/11 13:53:13.934123 3ms 0 main@complex||examples/complex.rs:86[INFO] limit running0 !
1062022/11/11 13:53:13.934123 3ms logger@ftlog::appender::file||src/appender/file.rs:255[INFO] Log file deleted: current-20221111T1352.log
1072022/11/11 13:53:14.939123 0ms main@complex||examples/complex.rs:85[INFO] running 1!
1082022/11/11 13:53:15.939123 0ms main@complex||examples/complex.rs:85[INFO] running 2!
1092022/11/11 13:53:16.943123 0ms main@complex||examples/complex.rs:85[INFO] running 3!
1102022/11/11 13:53:16.943123 0ms 2 main@complex||examples/complex.rs:86[INFO] limit running3 !
1112022/11/11 13:53:17.945123 0ms main@complex||examples/complex.rs:85[INFO] running 4!
1122022/11/11 13:53:18.946123 0ms main@complex||examples/complex.rs:85[INFO] running 5!
1132022/11/11 13:53:19.951123 0ms main@complex||examples/complex.rs:85[INFO] running 6!
1142022/11/11 13:53:19.951123 0ms 2 main@complex||examples/complex.rs:86[INFO] limit running6 !
1152022/11/11 13:53:20.956123 0ms main@complex||examples/complex.rs:85[INFO] running 7!
1162022/11/11 13:53:21.961123 0ms main@complex||examples/complex.rs:85[INFO] running 8!
1172022/11/11 13:53:22.966123 0ms main@complex||examples/complex.rs:85[INFO] running 9!
1182022/11/11 13:53:22.966123 4ms 2 main@complex||examples/complex.rs:86[INFO] limit running9 !
119
120
121Default style example:
1222022-04-11 15:08:19.847+08 0ms INFO main@src/main.rs:25 Hello, world!
1232022-04-11 15:08:19.847+08 0ms INFO main@src/main.rs:28 running 0!
1242022-04-11 15:08:19.847+08 0ms 0 INFO main@src/main.rs:29 limit running0 !
1252022-04-11 15:08:20.849+08 0ms INFO main@src/main.rs:28 running 1!
1262022-04-11 15:08:21.852+08 0ms INFO main@src/main.rs:28 running 2!
1272022-04-11 15:08:22.857+08 0ms INFO main@src/main.rs:28 running 3!
1282022-04-11 15:08:22.857+08 0ms 2 INFO main@src/main.rs:29 limit running3 !
1292022-04-11 15:08:23.862+08 0ms INFO main@src/main.rs:28 running 4!
1302022-04-11 15:08:24.864+08 0ms INFO main@src/main.rs:28 running 5!
131 */