1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use std::fmt::Display;

use ftlog::{
    appender::{file::Period, FileAppender},
    info, FtLogFormat,
};
use log::{Level, LevelFilter, Record};
use time::Duration;
fn init() {
    // Custom log style. Datetime format is fixed for performance

    // A formatter defines how to build a message.
    // Since Formatting message into string can slow down the log macro call,
    // the idomatic way is to send required field as is to log thread, and build
    // message in log thread.
    struct MyFormatter;
    impl FtLogFormat for MyFormatter {
        fn msg(&self, record: &Record) -> Box<dyn Send + Sync + std::fmt::Display> {
            Box::new(Msg {
                level: record.level(),
                thread: std::thread::current().name().map(|n| n.to_string()),
                file: record.file_static(),
                line: record.line(),
                args: format!("{}", record.args()),
                module_path: record.module_path_static(),
            })
        }
    }

    // Store necessary field, define how to build into string with `Display` trait.
    struct Msg {
        level: Level,
        thread: Option<String>,
        file: Option<&'static str>,
        line: Option<u32>,
        args: String,
        module_path: Option<&'static str>,
    }

    impl Display for Msg {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            f.write_str(&format!(
                "{}@{}||{}:{}[{}] {}",
                self.thread.as_ref().map(|x| x.as_str()).unwrap_or(""),
                self.module_path.unwrap_or(""),
                self.file.unwrap_or(""),
                self.line.unwrap_or(0),
                self.level,
                self.args
            ))
        }
    }

    ftlog::Builder::new()
        // use our own format
        .format(MyFormatter)
        // global max log level
        .max_log_level(LevelFilter::Info)
        // define root appender, pass None would write to stderr
        .root(FileAppender::rotate_with_expire(
            "./current.log",
            Period::Day,
            Duration::days(7),
        ))
        // ---------- configure additional filter ----------
        // write to "ftlog-appender" appender, with different level filter
        .filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
        // write to root appender, but with different level filter
        .filter("ftlog", None, LevelFilter::Trace)
        // write to "ftlog" appender, with default level filter
        .filter("ftlog::appender::file", "ftlog", None)
        // ----------  configure additional appender ----------
        // new appender
        .appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
        // new appender, rotate to new file every Day
        .appender("ftlog", FileAppender::rotate("ftlog.log", Period::Day))
        .try_init()
        .expect("logger build or set failed");
}

fn main() {
    init();
    info!("Hello, world!");
    for i in 0..120 {
        info!("running {}!", i);
        info!(limit=3000; "limit running{} !", i);
        std::thread::sleep(std::time::Duration::from_secs(1));
    }
    std::thread::sleep(std::time::Duration::from_secs(1));
}

/*
Output:

2022-11-11 13:53:13.933+08 0ms logger@ftlog||src/lib.rs:439[WARN] Logs with level more verbose than INFO will be ignored in `ftlog`
2022-11-11 13:53:13.933+08 0ms main@complex||examples/complex.rs:83[INFO] Hello, world!
2022-11-11 13:53:13.934+08 1ms main@complex||examples/complex.rs:85[INFO] running 0!
2022-11-11 13:53:13.934+08 3ms 0 main@complex||examples/complex.rs:86[INFO] limit running0 !
2022-11-11 13:53:13.934+08 3ms logger@ftlog::appender::file||src/appender/file.rs:255[INFO] Log file deleted: current-20221111T1352.log
2022-11-11 13:53:14.939+08 0ms main@complex||examples/complex.rs:85[INFO] running 1!
2022-11-11 13:53:15.939+08 0ms main@complex||examples/complex.rs:85[INFO] running 2!
2022-11-11 13:53:16.943+08 0ms main@complex||examples/complex.rs:85[INFO] running 3!
2022-11-11 13:53:16.943+08 0ms 2 main@complex||examples/complex.rs:86[INFO] limit running3 !
2022-11-11 13:53:17.945+08 0ms main@complex||examples/complex.rs:85[INFO] running 4!
2022-11-11 13:53:18.946+08 0ms main@complex||examples/complex.rs:85[INFO] running 5!
2022-11-11 13:53:19.951+08 0ms main@complex||examples/complex.rs:85[INFO] running 6!
2022-11-11 13:53:19.951+08 0ms 2 main@complex||examples/complex.rs:86[INFO] limit running6 !
2022-11-11 13:53:20.956+08 0ms main@complex||examples/complex.rs:85[INFO] running 7!
2022-11-11 13:53:21.961+08 0ms main@complex||examples/complex.rs:85[INFO] running 8!
2022-11-11 13:53:22.966+08 0ms main@complex||examples/complex.rs:85[INFO] running 9!
2022-11-11 13:53:22.966+08 4ms 2 main@complex||examples/complex.rs:86[INFO] limit running9 !


Default style example:
2022-04-11 15:08:19.847+08 0ms INFO main@src/main.rs:25 Hello, world!
2022-04-11 15:08:19.847+08 0ms INFO main@src/main.rs:28 running 0!
2022-04-11 15:08:19.847+08 0ms 0 INFO main@src/main.rs:29 limit running0 !
2022-04-11 15:08:20.849+08 0ms INFO main@src/main.rs:28 running 1!
2022-04-11 15:08:21.852+08 0ms INFO main@src/main.rs:28 running 2!
2022-04-11 15:08:22.857+08 0ms INFO main@src/main.rs:28 running 3!
2022-04-11 15:08:22.857+08 0ms 2 INFO main@src/main.rs:29 limit running3 !
2022-04-11 15:08:23.862+08 0ms INFO main@src/main.rs:28 running 4!
2022-04-11 15:08:24.864+08 0ms INFO main@src/main.rs:28 running 5!
 */