如何访问跟踪范围中字段的值?

Bos*_*Man 6 rust rust-tracing

我在项目中使用跟踪库,但有一件事我无法弄清楚:如何访问我的 中的值(我在创建它时在跨度中设置的值)Layer

我的图层看起来像这样:

impl<S> Layer<S> for CustomLayer where S: Subscriber {
    fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
        Interest::sometimes() //hardcoding so enabled() will be called everytime a span is created
    }

    fn enabled(&self, metadata: &Metadata<'_>, ctx: Context<'_, S>) -> bool {
        if metadata.is_span() {
            // How do I access value of key here?
            if value == X {
                true
            } else if value == Y {
                false
            }
        }
        true // default
    }
}
Run Code Online (Sandbox Code Playgroud)

kmd*_*eko 3

Span如果您有权访问 a 中的数据ValueSet(如在new_span()on_new_span()via中找到Attributes)或其Record条目(如在record()或中找到on_record()),则可以访问 a 中的数据。这样您就可以使用访客模式来查找您想要的信息。这是一个简单的实现,用于检查字段是否存在及其值是否是匹配的字符串:

use std::fmt::Debug;
use tracing::field::{ValueSet, Visit, Field};
use tracing::span::Record;

struct MatchStrVisitor<'a> {
    field: &'a str,
    value: &'a str,
    matched: bool,
}

impl Visit for MatchStrVisitor<'_> {
    fn record_debug(&mut self, _field: &Field, _value: &dyn Debug) {}
    fn record_str(&mut self, field: &Field, value: &str) {
        if field.name() == self.field && value == self.value {
            self.matched = true;
        }
    }
}

fn value_in_valueset(valueset: &ValueSet<'_>, field: &str, value: &str) -> bool {
    let mut visitor = MatchStrVisitor { field, value, matched: false };
    valueset.record(&mut visitor);
    visitor.matched
}

fn value_in_record(record: &Record<'_>, field: &str, value: &str) -> bool {
    let mut visitor = MatchStrVisitor { field, value, matched: false };
    record.record(&mut visitor);
    visitor.matched
}
Run Code Online (Sandbox Code Playgroud)

这是相当初级的,但希望能展示什么是可能的。需要注意的一件事是,存储的“值”要么是原始值(i64u64boolstr等),要么是通过 类型擦除的形式&dyn Debug。这些是您可以从访问者那里收到的唯一类型的值。


特别针对 OP 的情况,如本期所述,您无法在方法中访问此信息enabled(),因为这是在记录任何值之前发生的。您需要在new_span()方法中做出决定,并通过注册表使用跨度扩展来跟踪您是否认为该跨度在其他方法中“启用”。

这是另一个基本示例:

use tracing::span::Attributes;
use tracing::{Subscriber, Metadata, Id, Event};
use tracing::subscriber::Interest;
use tracing_subscriber::layer::{Context, Layer};
use tracing_subscriber::registry::LookupSpan;

struct CustomLayer;
struct CustomLayerEnabled;

impl<S> Layer<S> for CustomLayer where S: Subscriber + for <'a> LookupSpan<'a> {
    fn register_callsite(&self, _metadata: &'static Metadata<'static>) -> Interest {
        Interest::sometimes()
    }

    fn enabled(&self, metadata: &Metadata<'_>, _ctx: Context<'_, S>) -> bool {
        metadata.is_span()
    }

    fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
        if value_in_valueset(attrs.values(), "myfield", "myvalue") {
            ctx.span(id).unwrap().extensions_mut().insert(CustomLayerEnabled);
        }
    }

    fn on_event(&self, event: &Event<'_>, ctx: Context<'_, S>) {
        let span_id = event.parent().unwrap();
        if let None = ctx.span(span_id).unwrap().extensions().get::<CustomLayerEnabled>() {
            return;
        }

        // ... rest of your logic
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:我已经完全重写了这个答案,从评论和我新发现的经验中获取信息。