For a list of documents, see: Rust Mobile Complex Graphics Rendering Project Development Series summary (table of Contents)
(Last update: 2018-12-20 added [Log color]) Based on the usage summary of log, ENV_LOGGER, fern, etc., detailed configuration suggestions refer to the official instructions.
Add third-party log library dependencies to the project
To Cargo. Toml, log is the standard library for logging requirements of Rust projects. Env_logger provides a specific implementation, similar to the policy pattern: Log defines the operations, and env_logger implements the concrete behavior, making it easy to switch to another library that implements the log-defined interface, such as Daboross /fern.
[dependencies]
log = "0.4.0"
env_logger = "0.6.0"
Copy the code
Env_log configuration
The following describes the env_log configuration for our project. Error: Changing format causes terminal logs to be colorless.
Set the output time to the local time
Env_logger uses 0 time zone by default, while Beijing is east zone 8. Each log output is less than 8 hours, so it is inconvenient to analyze logs if the time is not matched. 0 time zone for example:
INFO 2018-11-18T02:00:08Z: webgpu-native::registry: env_logger initialized.
Copy the code
The example code of env_logger output local time is given below, referring to DCjanus/ Nabu. It can be used for ENv_logger by using Flexi_LOGGER with slight adjustment. The key to adding more customization information is to modify writeln! Macro.
#[macro_use]
extern crate log;
extern crate chrono;
extern crate env_logger;
fn init_log() {
use chrono::Local;
use std::io::Write;
let env = env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "trace");
env_logger::Builder::from_env(env)
.format(|buf, record| {
writeln!(
buf,
"{} {} [{}] {}",
Local::now().format("%Y-%m-%d %H:%M:%S"),
record.level(),
record.module_path().unwrap_or("<unnamed>"), &record.args() ) }) .init(); info! ("env_logger initialized.");
}
Copy the code
The above code must start at fn main() or lazy_static, otherwise the initial part of the log will not be affected by the new configuration. The log configuration placed in lazy_static needs to be manually enabled, for example
/ / define lazy_static! { pub(crate) static ref HUB: Hub = { init_log(); Hub::default() }; } // Call the HUB first in an entry function and "force" it to execute the lazy_static block fnentry_point() { &*HUB; // "force" execution of the lazy_static block hub.some_method (); // Info! () and so on can be normally output to a file or console}Copy the code
As an example, the following information is displayed:
[2018-11-18T02:00:08z INFO webGPU-native ::registry] env_logger initialized. // 2018-11-1809:27:43 INFO [webgpu-native::registry] env_logger initialized.Copy the code
Add the line number to the log
writeln!(
buf,
"{} {} / {}, {} {}",
Local::now().format("%Y-%m-%d %H:%M:%S"),
record.level(),
record.module_path().unwrap_or("<unnamed>"),
record.line().unwrap_or(0),
&record.args()
)
Copy the code
Execute the display:
2018-11-18 10:38:41 INFO [webgpu-native::registry:87] env_logger initialized.
Copy the code
Adding a log file name
writeln!(
buf,
"{} {} / {}, {}, {} {}",
Local::now().format("%Y-%m-%d %H:%M:%S"),
record.level(),
record.module_path().unwrap_or("<unnamed>"),
record.line().unwrap_or(0),
&record.args()
)
Copy the code
Execute the display:
2018-11-18 10:38:48 INFO [webgpu-native::registry:webgpu-native/src/registry.rs:87] env_logger initialized.
Copy the code
Log levels are aligned left and right
- The left
writeln!( buf, "{: < 5} {} / {}, {} {}", record.level(), // same as previous content ) Copy the code
- Align right
writeln!( buf, "{: > 5} {} / {}, {} {}", record.level(), // same as previous content ) Copy the code
What is the easiest way to pad a string with 0 to the left?
Log color
Without changing format, env_LOGGER uses different colors to mark level logs by default. The previous modification makes this feature “invalid”, which is not intuitive. Of course, CLion and others can use Grep Console plug-in to color the log. If it is executed in Terminal, we have to change the format to add color. Env_logger-0.6.0 / SRC/FMT /mod. Rs DefaultFormatter source code.
use std::io::Write;
let env = env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "trace");
let mut builder = env_logger::Builder::from_env(env);
println!("builder = {:? }", builder);
builder
.format(|buf, record| {
let level = { buf.default_styled_level(record.level()) };
write!(buf, "{}".format_args!("{: > 5}", level));
writeln!(buf, "{}", &record.args())
})
.init();
Copy the code
Filtering log Levels
env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "trace");
Copy the code
Filter_or () can be configured with the following built-in values to filter different levels of logs. In fact, we can also add filter tag:
- “trace”
- “info”
- “debug”
- “warn”
- “error”
You can also pass command line arguments during program execution for filtering:
$ RUST_LOG=info ./main
[2018-11-03T06:09:06Z INFO default] starting up
Copy the code
Combined filtration condition
Add depX=Y to filter all logs at the highest level. For example, if the log level is higher than info or debug, the log level is higher than info.
RUST_LOG=info,dep1=debug ./main
Copy the code
Dynamic Filtering information
In complex projects, there are often multiple modules. As a developer of one module, it is very common to filter out the logs of other modules in order to locate the problems of the module he is in charge of. Since the whole project usually uses the same log library, it is obviously unreasonable to comment the log output of other modules line by line. In addition, while the console can do filtering, multi-conditional filtering rules can be difficult to write and may not be supported by log viewing systems. In fact, we can add filtering logic to the format() we have been modifying, for example:
format(|buf, record| {
// special format for debug messages coming from our own crate.
if record.level() > log::LevelFilter::Info && record.target() == "my_module"{ write! (...). }else if/* some condition */ { write! (...). }else if/* some condition 2*/ { write! (...). }else{ write! (...). }}Copy the code
The implementation of the filtering logic is fern/cmd-program.rs.
Fern, another option for env_logger
daboross/fern
Simple, efficient logging for Rust
Fern is much more intuitive to configure (as shown below) and I haven’t tested its performance against ENv_Logger yet.
// Configure logger at runtime
fern::Dispatch::new()
// Perform allocation-free log formatting
.format(|out, message, record| {
out.finish(format_args!(
"[{}] [] {} {} {}",
chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"),
record.target(),
record.level(),
message
))
})
// Add blanket level filter -
.level(log::LevelFilter::Debug)
// - and per-module overrides
.level_for("hyper", log::LevelFilter::Info)
// Output to stdout, files, and other Dispatch configurations
.chain(std::io::stdout())
.chain(fern::log_file("output.log")?// Apply globally.apply()? ;// and log using log crate macros!info! ("helllo, world!");
Copy the code
Improving log Performance
todo