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 */