Builder

Struct Builder 

Source
pub struct Builder { /* private fields */ }
Expand description

Ftlog builder

let logger = ftlog::builder()
    // use our own format
    .format(ftlog::FtLogFormatter)
    // global max log level
    .max_log_level(LevelFilter::Info)
    // define root appender, pass anything that is Write and Send
    // omit `Builder::root` to 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))
    .build()
    .expect("logger build failed");

§Local timezone

For performance reason, ftlog only retrieve timezone info once and use this local timezone offset forever. Thus timestamp in log does not aware of timezone change by OS.

Implementations§

Source§

impl Builder

Source

pub fn new() -> Builder

Create a ftlog builder with default settings:

  • global log level: INFO
  • root log level: INFO
  • default formatter: FtLogFormatter
  • output to stderr
  • bounded channel between worker thread and log thread, with a size limit of 100_000
  • discard excessive log messages
  • log with timestamp of local timezone
Examples found in repository?
examples/lazy-bench.rs (line 34)
33fn main() {
34    let _guard = ftlog::Builder::new()
35        .root(std::io::sink())
36        .bounded(100_000, false)
37        // .unbounded()
38        .build()
39        .unwrap()
40        .init()
41        .unwrap();
42    run!("static string", {
43        ftlog::info!("ftlog message");
44    });
45    run!("with i32", {
46        ftlog::info!("ftlog: {}", 0i32);
47    });
48    run!("limit with i32", {
49        ftlog::info!(limit=3i64; "ftlog: {}", 0i32);
50    });
51}
More examples
Hide additional examples
examples/string-bench.rs (line 49)
48fn main() {
49    let _guard = ftlog::Builder::new()
50        .root(std::io::sink())
51        .format(StringFormatter)
52        .bounded(100_000, false)
53        // .unbounded()
54        .build()
55        .unwrap()
56        .init()
57        .unwrap();
58    run!("static string", {
59        ftlog::info!("ftlog message");
60    });
61    run!("with i32", {
62        ftlog::info!("ftlog: {}", 0i32);
63    });
64    run!("limit with i32", {
65        ftlog::info!(limit=3i64; "ftlog: {}", 0i32);
66    });
67}
examples/ftlog.rs (line 15)
8fn init() -> LoggerGuard {
9    // Rotate every day, clean stale logs that were modified 7 days ago on each rotation
10    let writer = FileAppender::builder()
11        .path("./current.log")
12        .rotate(Period::Minute)
13        .expire(Duration::minutes(4))
14        .build();
15    ftlog::Builder::new()
16        // global max log level
17        .max_log_level(LevelFilter::Info)
18        // define root appender, pass None would write to stderr
19        .root(writer)
20        // write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
21        .filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
22        .appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
23        .try_init()
24        .expect("logger build or set failed")
25}
examples/multi-dest.rs (line 15)
8fn init() -> LoggerGuard {
9    // Rotate every day, clean stale logs that were modified 7 days ago on each rotation
10    let writer = FileAppender::builder()
11        .path("./current.log")
12        .rotate(Period::Minute)
13        .expire(Duration::minutes(2))
14        .build();
15    ftlog::Builder::new()
16        // global max log level
17        .max_log_level(LevelFilter::Info)
18        // define root appender, pass None would write to stderr
19        .root(ChainAppenders::new(vec![
20            Box::new(writer),
21            Box::new(std::io::stdout()),
22        ]))
23        // write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
24        .filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
25        .appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
26        .try_init()
27        .expect("logger build or set failed")
28}
examples/custom-format.rs (line 58)
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}
Source

pub fn format<F: FtLogFormat + 'static>(self, format: F) -> Builder

Set custom formatter

Examples found in repository?
examples/string-bench.rs (line 51)
48fn main() {
49    let _guard = ftlog::Builder::new()
50        .root(std::io::sink())
51        .format(StringFormatter)
52        .bounded(100_000, false)
53        // .unbounded()
54        .build()
55        .unwrap()
56        .init()
57        .unwrap();
58    run!("static string", {
59        ftlog::info!("ftlog message");
60    });
61    run!("with i32", {
62        ftlog::info!("ftlog: {}", 0i32);
63    });
64    run!("limit with i32", {
65        ftlog::info!(limit=3i64; "ftlog: {}", 0i32);
66    });
67}
More examples
Hide additional examples
examples/custom-format.rs (line 60)
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}
Source

pub fn time_format(self, format: OwnedFormatItem) -> Builder

Set custom datetime formatter

Examples found in repository?
examples/custom-format.rs (line 62)
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}
Source

pub fn bounded(self, size: usize, block_when_full: bool) -> Builder

bound channel between worker thread and log thread

When block_when_full is true, it will block current thread where log macro (e.g. log::info) is called until log thread is able to handle new message. Otherwises, excessive log messages will be discarded.

By default, excessive log messages is discarded silently. To show how many log messages have been dropped, see Builder::print_omitted_count().

Examples found in repository?
examples/lazy-bench.rs (line 36)
33fn main() {
34    let _guard = ftlog::Builder::new()
35        .root(std::io::sink())
36        .bounded(100_000, false)
37        // .unbounded()
38        .build()
39        .unwrap()
40        .init()
41        .unwrap();
42    run!("static string", {
43        ftlog::info!("ftlog message");
44    });
45    run!("with i32", {
46        ftlog::info!("ftlog: {}", 0i32);
47    });
48    run!("limit with i32", {
49        ftlog::info!(limit=3i64; "ftlog: {}", 0i32);
50    });
51}
More examples
Hide additional examples
examples/string-bench.rs (line 52)
48fn main() {
49    let _guard = ftlog::Builder::new()
50        .root(std::io::sink())
51        .format(StringFormatter)
52        .bounded(100_000, false)
53        // .unbounded()
54        .build()
55        .unwrap()
56        .init()
57        .unwrap();
58    run!("static string", {
59        ftlog::info!("ftlog message");
60    });
61    run!("with i32", {
62        ftlog::info!("ftlog: {}", 0i32);
63    });
64    run!("limit with i32", {
65        ftlog::info!(limit=3i64; "ftlog: {}", 0i32);
66    });
67}
Source

pub fn print_omitted_count(self, print: bool) -> Builder

whether to print the number of omitted logs if channel to log thread is bounded, and set to discard excessive log messages

Source

pub fn unbounded(self) -> Builder

set channel size to unbound

ATTENTION: too much log message will lead to huge memory consumption, as log messages are queued to be handled by log thread. When log message exceed the current channel size, it will double the size by default, Since channel expansion asks for memory allocation, log calls can be slow down.

Source

pub fn appender( self, name: &'static str, appender: impl Write + Send + 'static, ) -> Builder

Add an additional appender with a name

Combine with Builder::filter(), ftlog can output log in different module path to different output target.

Examples found in repository?
examples/ftlog.rs (line 22)
8fn init() -> LoggerGuard {
9    // Rotate every day, clean stale logs that were modified 7 days ago on each rotation
10    let writer = FileAppender::builder()
11        .path("./current.log")
12        .rotate(Period::Minute)
13        .expire(Duration::minutes(4))
14        .build();
15    ftlog::Builder::new()
16        // global max log level
17        .max_log_level(LevelFilter::Info)
18        // define root appender, pass None would write to stderr
19        .root(writer)
20        // write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
21        .filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
22        .appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
23        .try_init()
24        .expect("logger build or set failed")
25}
More examples
Hide additional examples
examples/multi-dest.rs (line 25)
8fn init() -> LoggerGuard {
9    // Rotate every day, clean stale logs that were modified 7 days ago on each rotation
10    let writer = FileAppender::builder()
11        .path("./current.log")
12        .rotate(Period::Minute)
13        .expire(Duration::minutes(2))
14        .build();
15    ftlog::Builder::new()
16        // global max log level
17        .max_log_level(LevelFilter::Info)
18        // define root appender, pass None would write to stderr
19        .root(ChainAppenders::new(vec![
20            Box::new(writer),
21            Box::new(std::io::stdout()),
22        ]))
23        // write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
24        .filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
25        .appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
26        .try_init()
27        .expect("logger build or set failed")
28}
examples/custom-format.rs (line 82)
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}
Source

pub fn filter<A: Into<Option<&'static str>>, L: Into<Option<LevelFilter>>>( self, module_path: &'static str, appender: A, level: L, ) -> Builder

Add a filter to redirect log to different output target (e.g. stderr, stdout, different files).

ATTENTION: level more verbose than Builder::max_log_level will be ignored. Say we configure max_log_level to INFO, and even if filter’s level is set to DEBUG, ftlog will still log up to INFO.

Examples found in repository?
examples/ftlog.rs (line 21)
8fn init() -> LoggerGuard {
9    // Rotate every day, clean stale logs that were modified 7 days ago on each rotation
10    let writer = FileAppender::builder()
11        .path("./current.log")
12        .rotate(Period::Minute)
13        .expire(Duration::minutes(4))
14        .build();
15    ftlog::Builder::new()
16        // global max log level
17        .max_log_level(LevelFilter::Info)
18        // define root appender, pass None would write to stderr
19        .root(writer)
20        // write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
21        .filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
22        .appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
23        .try_init()
24        .expect("logger build or set failed")
25}
More examples
Hide additional examples
examples/multi-dest.rs (line 24)
8fn init() -> LoggerGuard {
9    // Rotate every day, clean stale logs that were modified 7 days ago on each rotation
10    let writer = FileAppender::builder()
11        .path("./current.log")
12        .rotate(Period::Minute)
13        .expire(Duration::minutes(2))
14        .build();
15    ftlog::Builder::new()
16        // global max log level
17        .max_log_level(LevelFilter::Info)
18        // define root appender, pass None would write to stderr
19        .root(ChainAppenders::new(vec![
20            Box::new(writer),
21            Box::new(std::io::stdout()),
22        ]))
23        // write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
24        .filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
25        .appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
26        .try_init()
27        .expect("logger build or set failed")
28}
examples/custom-format.rs (line 75)
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}
Source

pub fn root(self, writer: impl Write + Send + 'static) -> Builder

Configure the default log output target.

Omit this method will output to stderr.

Examples found in repository?
examples/lazy-bench.rs (line 35)
33fn main() {
34    let _guard = ftlog::Builder::new()
35        .root(std::io::sink())
36        .bounded(100_000, false)
37        // .unbounded()
38        .build()
39        .unwrap()
40        .init()
41        .unwrap();
42    run!("static string", {
43        ftlog::info!("ftlog message");
44    });
45    run!("with i32", {
46        ftlog::info!("ftlog: {}", 0i32);
47    });
48    run!("limit with i32", {
49        ftlog::info!(limit=3i64; "ftlog: {}", 0i32);
50    });
51}
More examples
Hide additional examples
examples/string-bench.rs (line 50)
48fn main() {
49    let _guard = ftlog::Builder::new()
50        .root(std::io::sink())
51        .format(StringFormatter)
52        .bounded(100_000, false)
53        // .unbounded()
54        .build()
55        .unwrap()
56        .init()
57        .unwrap();
58    run!("static string", {
59        ftlog::info!("ftlog message");
60    });
61    run!("with i32", {
62        ftlog::info!("ftlog: {}", 0i32);
63    });
64    run!("limit with i32", {
65        ftlog::info!(limit=3i64; "ftlog: {}", 0i32);
66    });
67}
examples/ftlog.rs (line 19)
8fn init() -> LoggerGuard {
9    // Rotate every day, clean stale logs that were modified 7 days ago on each rotation
10    let writer = FileAppender::builder()
11        .path("./current.log")
12        .rotate(Period::Minute)
13        .expire(Duration::minutes(4))
14        .build();
15    ftlog::Builder::new()
16        // global max log level
17        .max_log_level(LevelFilter::Info)
18        // define root appender, pass None would write to stderr
19        .root(writer)
20        // write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
21        .filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
22        .appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
23        .try_init()
24        .expect("logger build or set failed")
25}
examples/multi-dest.rs (lines 19-22)
8fn init() -> LoggerGuard {
9    // Rotate every day, clean stale logs that were modified 7 days ago on each rotation
10    let writer = FileAppender::builder()
11        .path("./current.log")
12        .rotate(Period::Minute)
13        .expire(Duration::minutes(2))
14        .build();
15    ftlog::Builder::new()
16        // global max log level
17        .max_log_level(LevelFilter::Info)
18        // define root appender, pass None would write to stderr
19        .root(ChainAppenders::new(vec![
20            Box::new(writer),
21            Box::new(std::io::stdout()),
22        ]))
23        // write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
24        .filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
25        .appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
26        .try_init()
27        .expect("logger build or set failed")
28}
examples/custom-format.rs (lines 66-72)
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}
Source

pub fn max_log_level(self, level: LevelFilter) -> Builder

Set max log level

Logs with level more verbose than this will not be sent to log thread.

Examples found in repository?
examples/ftlog.rs (line 17)
8fn init() -> LoggerGuard {
9    // Rotate every day, clean stale logs that were modified 7 days ago on each rotation
10    let writer = FileAppender::builder()
11        .path("./current.log")
12        .rotate(Period::Minute)
13        .expire(Duration::minutes(4))
14        .build();
15    ftlog::Builder::new()
16        // global max log level
17        .max_log_level(LevelFilter::Info)
18        // define root appender, pass None would write to stderr
19        .root(writer)
20        // write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
21        .filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
22        .appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
23        .try_init()
24        .expect("logger build or set failed")
25}
More examples
Hide additional examples
examples/multi-dest.rs (line 17)
8fn init() -> LoggerGuard {
9    // Rotate every day, clean stale logs that were modified 7 days ago on each rotation
10    let writer = FileAppender::builder()
11        .path("./current.log")
12        .rotate(Period::Minute)
13        .expire(Duration::minutes(2))
14        .build();
15    ftlog::Builder::new()
16        // global max log level
17        .max_log_level(LevelFilter::Info)
18        // define root appender, pass None would write to stderr
19        .root(ChainAppenders::new(vec![
20            Box::new(writer),
21            Box::new(std::io::stdout()),
22        ]))
23        // write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
24        .filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
25        .appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
26        .try_init()
27        .expect("logger build or set failed")
28}
examples/custom-format.rs (line 64)
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}
Source

pub fn root_log_level(self, level: LevelFilter) -> Builder

Set max log level

Logs with level more verbose than this will not be sent to log thread.

Source

pub fn local_timezone(self) -> Builder

Log with timestamp of local timezone

Timezone is fixed after logger setup for the following reasons:

  1. time v0.3 currently do not allow access to local offset for multithread process in unix-like OS.
  2. timezone retrieval from OS is quite slow (around several microsecond) compare with utc timestamp retrieval (around tens of nanoseconds)
Source

pub fn utc(self) -> Builder

Log with timestamp of UTC timezone

Source

pub fn fixed_timezone(self, timezone: UtcOffset) -> Builder

Log with timestamp of fixed timezone

Source

pub fn timezone(self, timezone: LogTimezone) -> Builder

Specify the timezone of log messages

Source

pub fn build(self) -> Result<Logger, IoError>

Finish building ftlog logger

The call spawns a log thread to formatting log message into string, and write to output target.

Examples found in repository?
examples/lazy-bench.rs (line 38)
33fn main() {
34    let _guard = ftlog::Builder::new()
35        .root(std::io::sink())
36        .bounded(100_000, false)
37        // .unbounded()
38        .build()
39        .unwrap()
40        .init()
41        .unwrap();
42    run!("static string", {
43        ftlog::info!("ftlog message");
44    });
45    run!("with i32", {
46        ftlog::info!("ftlog: {}", 0i32);
47    });
48    run!("limit with i32", {
49        ftlog::info!(limit=3i64; "ftlog: {}", 0i32);
50    });
51}
More examples
Hide additional examples
examples/string-bench.rs (line 54)
48fn main() {
49    let _guard = ftlog::Builder::new()
50        .root(std::io::sink())
51        .format(StringFormatter)
52        .bounded(100_000, false)
53        // .unbounded()
54        .build()
55        .unwrap()
56        .init()
57        .unwrap();
58    run!("static string", {
59        ftlog::info!("ftlog message");
60    });
61    run!("with i32", {
62        ftlog::info!("ftlog: {}", 0i32);
63    });
64    run!("limit with i32", {
65        ftlog::info!(limit=3i64; "ftlog: {}", 0i32);
66    });
67}
Source

pub fn try_init(self) -> Result<LoggerGuard, Box<dyn Error>>

try building and setting as global logger

Examples found in repository?
examples/stderr.rs (line 4)
3fn main() {
4    let _guard = ftlog::builder().try_init().unwrap();
5
6    info!("Hello, world!");
7    for i in 0..120 {
8        info!("running {}!", i);
9        info!(limit=3000i64; "limit running{} !", i);
10        std::thread::sleep(std::time::Duration::from_secs(1));
11    }
12}
More examples
Hide additional examples
examples/random_drop.rs (line 4)
3fn main() {
4    let _guard = ftlog::builder().try_init().unwrap();
5
6    // both `random_drop` and `drop` are recognized
7    for i in 0..10 {
8        info!(random_drop=0.0f32;"Always log: {}", i);
9        info!(drop=1.0f32; "Always log: {}", i);
10        info!(random_drop=0.9f32; "Randomly drop 90% of log calls: {}", i);
11    }
12}
examples/ftlog.rs (line 23)
8fn init() -> LoggerGuard {
9    // Rotate every day, clean stale logs that were modified 7 days ago on each rotation
10    let writer = FileAppender::builder()
11        .path("./current.log")
12        .rotate(Period::Minute)
13        .expire(Duration::minutes(4))
14        .build();
15    ftlog::Builder::new()
16        // global max log level
17        .max_log_level(LevelFilter::Info)
18        // define root appender, pass None would write to stderr
19        .root(writer)
20        // write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
21        .filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
22        .appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
23        .try_init()
24        .expect("logger build or set failed")
25}
examples/multi-dest.rs (line 26)
8fn init() -> LoggerGuard {
9    // Rotate every day, clean stale logs that were modified 7 days ago on each rotation
10    let writer = FileAppender::builder()
11        .path("./current.log")
12        .rotate(Period::Minute)
13        .expire(Duration::minutes(2))
14        .build();
15    ftlog::Builder::new()
16        // global max log level
17        .max_log_level(LevelFilter::Info)
18        // define root appender, pass None would write to stderr
19        .root(ChainAppenders::new(vec![
20            Box::new(writer),
21            Box::new(std::io::stdout()),
22        ]))
23        // write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
24        .filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
25        .appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
26        .try_init()
27        .expect("logger build or set failed")
28}
examples/custom-format.rs (line 85)
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}

Trait Implementations§

Source§

impl Default for Builder

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.