假设我有一个返回 a 的函数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(())
}
Run Code Online (Sandbox Code Playgroud)
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>`
Run Code Online (Sandbox Code Playgroud)
我认为这从根本上与 aSubscriber的处理任务不一致。我认为s的模块文档Layer说得很清楚:
\n\n\n
Subscriber中的特征代表tracing-core使用仪器所需的完整功能集tracing。这意味着单个Subscriber实例是收集跟踪的完整策略的独立实现;但这也意味着该Subscriber特质不能轻易地与其他特质组合Subscriber。特别是,
\nSubscribers 负责生成span ID 并将其分配给span。由于这些 ID 必须在当前跟踪的上下文中唯一标识一个跨度,这意味着在任何时间点 \xe2\x80\x94 对于给定线程可能只有一个跨度,Subscriber否则,将没有跨度的权威来源身份证。另一方面,大多数
\nSubscriberTrait\xe2\x80\x99s 功能是可组合的:任意数量的订阅者都可以观察事件、跨度进入和退出等,前提是跨度 ID 具有单一的权威来源。该Layer特质代表了该Subscriber行为的可组合子集;它可以观察事件和跨度,但不分配 ID。
因此,如果可能的话,尝试将您的日志配置推广到Layers 而不是Subscribers。甚至已经有了一个impl Layer for Vec<L> where L: Layer实现。
我认为这种可表达性和可组合性是大多数相关箱子被实现为Layers 而不是s的原因Subscriber。甚至其中一些被列为“实现订阅者”的也使用层(例如tracing-gelf或tracing-forest)。