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
impl Builder
sourcepub fn new() -> Builder
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?
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
fn main() {
ftlog::Builder::new()
.root(std::io::sink())
.bounded(100_000, false)
// .unbounded()
.build()
.unwrap()
.init()
.unwrap();
run!("static string", {
ftlog::info!("ftlog message");
});
run!("with i32", {
ftlog::info!("ftlog: {}", 0i32);
});
run!("limit with i32", {
ftlog::info!(limit=3; "ftlog: {}", 0i32);
});
}More examples
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
fn main() {
ftlog::Builder::new()
.root(std::io::sink())
.format(StringFormatter)
.bounded(100_000, false)
// .unbounded()
.build()
.unwrap()
.init()
.unwrap();
run!("static string", {
ftlog::info!("ftlog message");
});
run!("with i32", {
ftlog::info!("ftlog: {}", 0i32);
});
run!("limit with i32", {
ftlog::info!(limit=3; "ftlog: {}", 0i32);
});
}7 8 9 10 11 12 13 14 15 16 17 18 19 20
fn init() {
// Rotate every day, clean stale logs that were modified 7 days ago on each rotation
let writer = FileAppender::rotate_with_expire("./current.log", Period::Day, Duration::weeks(1));
ftlog::Builder::new()
// global max log level
.max_log_level(LevelFilter::Info)
// define root appender, pass None would write to stderr
.root(writer)
// write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
.filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
.appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
.try_init()
.expect("logger build or set failed");
}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
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");
}sourcepub fn format<F: FtLogFormat + 'static>(self, format: F) -> Builder
pub fn format<F: FtLogFormat + 'static>(self, format: F) -> Builder
Set custom formatter
Examples found in repository?
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
fn main() {
ftlog::Builder::new()
.root(std::io::sink())
.format(StringFormatter)
.bounded(100_000, false)
// .unbounded()
.build()
.unwrap()
.init()
.unwrap();
run!("static string", {
ftlog::info!("ftlog message");
});
run!("with i32", {
ftlog::info!("ftlog: {}", 0i32);
});
run!("limit with i32", {
ftlog::info!(limit=3; "ftlog: {}", 0i32);
});
}More examples
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
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");
}sourcepub fn bounded(self, size: usize, block_when_full: bool) -> Builder
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?
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
fn main() {
ftlog::Builder::new()
.root(std::io::sink())
.bounded(100_000, false)
// .unbounded()
.build()
.unwrap()
.init()
.unwrap();
run!("static string", {
ftlog::info!("ftlog message");
});
run!("with i32", {
ftlog::info!("ftlog: {}", 0i32);
});
run!("limit with i32", {
ftlog::info!(limit=3; "ftlog: {}", 0i32);
});
}More examples
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
fn main() {
ftlog::Builder::new()
.root(std::io::sink())
.format(StringFormatter)
.bounded(100_000, false)
// .unbounded()
.build()
.unwrap()
.init()
.unwrap();
run!("static string", {
ftlog::info!("ftlog message");
});
run!("with i32", {
ftlog::info!("ftlog: {}", 0i32);
});
run!("limit with i32", {
ftlog::info!(limit=3; "ftlog: {}", 0i32);
});
}sourcepub fn print_omitted_count(self, print: bool) -> Builder
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
sourcepub fn unbounded(self) -> Builder
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.
sourcepub fn appender(
self,
name: &'static str,
appender: impl Write + Send + 'static
) -> Builder
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?
7 8 9 10 11 12 13 14 15 16 17 18 19 20
fn init() {
// Rotate every day, clean stale logs that were modified 7 days ago on each rotation
let writer = FileAppender::rotate_with_expire("./current.log", Period::Day, Duration::weeks(1));
ftlog::Builder::new()
// global max log level
.max_log_level(LevelFilter::Info)
// define root appender, pass None would write to stderr
.root(writer)
// write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
.filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
.appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
.try_init()
.expect("logger build or set failed");
}More examples
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
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");
}sourcepub fn filter<A: Into<Option<&'static str>>, L: Into<Option<LevelFilter>>>(
self,
module_path: &'static str,
appender: A,
level: L
) -> Builder
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?
7 8 9 10 11 12 13 14 15 16 17 18 19 20
fn init() {
// Rotate every day, clean stale logs that were modified 7 days ago on each rotation
let writer = FileAppender::rotate_with_expire("./current.log", Period::Day, Duration::weeks(1));
ftlog::Builder::new()
// global max log level
.max_log_level(LevelFilter::Info)
// define root appender, pass None would write to stderr
.root(writer)
// write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
.filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
.appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
.try_init()
.expect("logger build or set failed");
}More examples
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
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");
}sourcepub fn root(self, writer: impl Write + Send + 'static) -> Builder
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?
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
fn main() {
ftlog::Builder::new()
.root(std::io::sink())
.bounded(100_000, false)
// .unbounded()
.build()
.unwrap()
.init()
.unwrap();
run!("static string", {
ftlog::info!("ftlog message");
});
run!("with i32", {
ftlog::info!("ftlog: {}", 0i32);
});
run!("limit with i32", {
ftlog::info!(limit=3; "ftlog: {}", 0i32);
});
}More examples
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
fn main() {
ftlog::Builder::new()
.root(std::io::sink())
.format(StringFormatter)
.bounded(100_000, false)
// .unbounded()
.build()
.unwrap()
.init()
.unwrap();
run!("static string", {
ftlog::info!("ftlog message");
});
run!("with i32", {
ftlog::info!("ftlog: {}", 0i32);
});
run!("limit with i32", {
ftlog::info!(limit=3; "ftlog: {}", 0i32);
});
}7 8 9 10 11 12 13 14 15 16 17 18 19 20
fn init() {
// Rotate every day, clean stale logs that were modified 7 days ago on each rotation
let writer = FileAppender::rotate_with_expire("./current.log", Period::Day, Duration::weeks(1));
ftlog::Builder::new()
// global max log level
.max_log_level(LevelFilter::Info)
// define root appender, pass None would write to stderr
.root(writer)
// write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
.filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
.appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
.try_init()
.expect("logger build or set failed");
}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
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");
}sourcepub fn max_log_level(self, level: LevelFilter) -> Builder
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?
7 8 9 10 11 12 13 14 15 16 17 18 19 20
fn init() {
// Rotate every day, clean stale logs that were modified 7 days ago on each rotation
let writer = FileAppender::rotate_with_expire("./current.log", Period::Day, Duration::weeks(1));
ftlog::Builder::new()
// global max log level
.max_log_level(LevelFilter::Info)
// define root appender, pass None would write to stderr
.root(writer)
// write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
.filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
.appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
.try_init()
.expect("logger build or set failed");
}More examples
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
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");
}sourcepub fn root_log_level(self, level: LevelFilter) -> Builder
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.
sourcepub fn local_timezone(self) -> Builder
pub fn local_timezone(self) -> Builder
Log with timestamp of local timezone
Timezone is fixed after logger setup for the following reasons:
timev0.3 currently do not allow access to local offset for multithread process in unix-like OS.- timezone retrieval from OS is quite slow (around several microsecond) compare with utc timestamp retrieval (around tens of nanoseconds)
sourcepub fn build(self) -> Result<Logger, IoError>
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?
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
fn main() {
ftlog::Builder::new()
.root(std::io::sink())
.bounded(100_000, false)
// .unbounded()
.build()
.unwrap()
.init()
.unwrap();
run!("static string", {
ftlog::info!("ftlog message");
});
run!("with i32", {
ftlog::info!("ftlog: {}", 0i32);
});
run!("limit with i32", {
ftlog::info!(limit=3; "ftlog: {}", 0i32);
});
}More examples
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
fn main() {
ftlog::Builder::new()
.root(std::io::sink())
.format(StringFormatter)
.bounded(100_000, false)
// .unbounded()
.build()
.unwrap()
.init()
.unwrap();
run!("static string", {
ftlog::info!("ftlog message");
});
run!("with i32", {
ftlog::info!("ftlog: {}", 0i32);
});
run!("limit with i32", {
ftlog::info!(limit=3; "ftlog: {}", 0i32);
});
}sourcepub fn try_init(self) -> Result<(), Box<dyn Error>>
pub fn try_init(self) -> Result<(), Box<dyn Error>>
try building and setting as global logger
Examples found in repository?
More examples
7 8 9 10 11 12 13 14 15 16 17 18 19 20
fn init() {
// Rotate every day, clean stale logs that were modified 7 days ago on each rotation
let writer = FileAppender::rotate_with_expire("./current.log", Period::Day, Duration::weeks(1));
ftlog::Builder::new()
// global max log level
.max_log_level(LevelFilter::Info)
// define root appender, pass None would write to stderr
.root(writer)
// write logs in ftlog::appender to "./ftlog-appender.log" instead of "./current.log"
.filter("ftlog::appender", "ftlog-appender", LevelFilter::Error)
.appender("ftlog-appender", FileAppender::new("ftlog-appender.log"))
.try_init()
.expect("logger build or set failed");
}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
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");
}