我仍是 Rust 的菜鸟,正在阅读有关可用的日志箱的信息。这个log
箱及其不同实现的某些方面对我来说就像魔术一样。以这个片段为例(摘自本文):
use log::debug;
use log::error;
use log::info;
use log::warn;
fn main() {
env_logger::init();
debug!("Mary has a little lamb");
error!("{}", "Its fleece was white as snow");
info!("{:?}", "And every where that Mary went");
warn!("{:#?}", "The lamb was sure to go");
}
env_logger
初始化后, 中的宏log
就可以立即使用了。 如何log
知道已定义记录器以及在哪里找到它? 如果同时定义了多个记录器,会发生什么情况? 它会如何选择? 在 的情况下env_logger
,第二次调用env_logger::init()
会导致线程崩溃,但这是一般规则吗?
在底层,特定的记录器实现将调用
log::set_logger
(或其他函数log
提供)来全局安装记录器。log
有一个全局(静态)&dyn Log
变量,用于保存对当前记录器的引用。log
未公开在安装全局记录器后替换它的方法;安装记录器的函数系列在第二次调用时全部失败。因此,您描述的具有多个活动记录器的场景是不可能的。该
log
板条箱维护一个全局记录器(&'static dyn Log
),默认情况下未初始化且未注册。当您使用 初始化日志记录后端时
env_logger::init()
,该后端通过调用 将自身注册为全局记录器log::set_logger()
。尝试初始化第二个后端通常会导致恐慌,因为log
要避免混淆如何以及在何处发送消息,并且它会假设第二个后端是意外错误。如果您根本没有初始化记录器后端,那么宏仍然会起作用,但它们将没有全局记录器来转发消息。
您可以在库包中包含
log
宏,这将允许用户选择和设置他们自己的全局记录器(如果他们愿意的话)。例如,假设你的板条箱
mister_t
有一个功能:任何使用者都
mister_t
可以像这样访问您的日志:或者他们可以默默地运行它,就像这样:
第一个将打印信息,后者将不记录任何内容但仍运行其余部分
foo
。它的设计灵活且直观,但单轨。如果您需要更复杂的日志处理,我建议您查看
tracing
。