假设我有一个返回Vec<Box<dyn Subscriber>>
的函数,我想将它们组合成一个单独的函数,并将其设置为默认订阅者。如何做到这一点?
我尝试做类似的事情,但我无法使类型匹配:
pub fn init_log(subscribers: Vec<Box<dyn Subscriber>>) -> Result<(), Error> {
use tracing_subscriber::prelude::*;
let mut layers: Vec<Box<dyn Layer<dyn Subscriber>>> = Vec::new();
for subscriber in subscribers.iter().drain(..) {
let layer: Box<dyn Layer<dyn Subscriber>> =
Box::new(tracing_subscriber::layer::Identity::new().with_subscriber(subscriber));
layers.push(layer);
}
let init_layer: Box<dyn Layer<dyn Subscriber>> =
Box::new(tracing_subscriber::layer::Identity::new());
let acc_subscriber: Layered<Box<dyn Layer<dyn Subscriber>>, _> =
tracing_subscriber::fmt().finish().with(init_layer);
let composed = layers
.drain(..)
.into_iter()
.fold(acc_subscriber, |acc, layer| acc.with(layer));
tracing::subscriber::set_global_default(composed);
Ok(())
}
error[E0277]: the trait bound `Box<dyn tracing::Subscriber>: tracing::Subscriber` is not satisfied
--> jormungandr\src\settings\logging.rs:97:85
|
97 | Box::new(tracing_subscriber::layer::Identity::new().with_subscriber(subscriber));
| ^^^^^^^^^^ the trait `tracing::Subscriber` is not implemented for `Box<dyn tracing::Subscriber>`
1条答案
按热度按时间7eumitmz1#
我认为这与
Subscriber
处理的任务根本不一致。我认为Layer
s的module documentation清楚地说明了这一点:tracing-core
中的Subscriber
trait表示使用tracing
插装所需的完整功能集。这意味着单个Subscriber
示例是完整的跟踪收集策略的自包含实现;但是这也意味着Subscriber
特征不能容易地与其他Subscriber
组合。特别是,
Subscriber
s负责生成跨度ID并将其分配给跨度。由于这些ID必须在当前跟踪的上下文中唯一标识一个span,这意味着在任何时间点,给定线程可能只有一个Subscriber
,否则,将没有span ID的权威来源。另一方面,
Subscriber
trait的大部分功能都是可组合的:只要存在单个授权的跨度ID源,任何数量的订户都可以观察事件、跨度进入和退出等。Layer
特征表示Subscriber
行为的可组合子集;它可以观察事件和跨度,但不分配ID。因此,如果可能的话,请尝试将日志配置一般化为
Layer
s,而不是Subscriber
s。甚至已经有了impl Layer for Vec<L> where L: Layer
的实现。我认为这种可表达性和可组合性是大多数Related Crates被实现为
Layer
s而不是Subscriber
s的原因。甚至一些被列为“实现订阅者”的应用程序也使用了层(如tracing-gelf或tracing-forest)。