rust 使用tokio跟踪获取父范围字段值

5gfr0r5j  于 2023-02-08  发布在  其他
关注(0)|答案(1)|浏览(163)

我尝试使用时雄跟踪来检测一个函数,获取它的参数,然后走到父级span并获取一些字段的值。我能够成功地通过创建一个新层来获取参数,如下所示:

impl<S> Layer<S> for MyTestLayer
where
    S: tracing::Subscriber,
    S: for<'lookup> tracing_subscriber::registry::LookupSpan<'lookup>,
{
    fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
        let span = ctx.span(id).unwrap();
        let mut visitor = MyVisitor{ ... };

        attrs.record(&mut visitor);
        ...
}

这看起来很有效,让我得到了预期spanattributes。然而,与访问者一起访问每个字段/值感觉我做错了什么。这是获取属性值的最佳方法吗?
在这里,我想从父span中获取两个字段。看起来我应该能够执行以下操作:

let parent = span.parent().unwrap();
let parent_fields = p.fields();
// ... Read the data from the fields?

然而,这似乎并不起作用,因为fields()提供了一个FieldSet,并且没有明显的访问ValueSet的值的权限。从父字段获取值的正确方法是什么?有更简单/更好的方法吗?

yqlxgs2m

yqlxgs2m1#

Attributes以及所包含的值 * 仅 * 在创建新范围时可用。tracing框架不会保留这些值以供检查,从而保持较低的开销。Subscriber负责持久化处理范围时所需的任何值。
幸运的是,有一些工具可以提供帮助。你已经在利用tracing-subscriberLayer生态系统,甚至还依赖于它的RegistryLookupSpan特性。注册表提供了一个通用的机制,用于通过Extensions存储跨度数据。
这意味着MyTestLayer应该存储以后处理父span时需要的任何数据,然后在处理子span时可以从注册表中获取这些数据。
下面是一个获取并持久化一个"test"字段值的示例,该值可以在以后查找:

use std::fmt::Debug;

use tracing::field::{Field, Visit};
use tracing::span::{Attributes, Id};
use tracing_subscriber::layer::{Context, Layer};

struct TestVisitor(Option<String>);

impl Visit for TestVisitor {
    fn record_debug(&mut self, _field: &Field, _value: &dyn Debug) {
        // do nothing
    }

    fn record_str(&mut self, field: &Field, value: &str) {
        if field.name() == "test" {
            self.0 = Some(value.to_owned());
        }
    }
}

struct Test(String);

pub struct MyTestLayer;

impl<S> Layer<S> for MyTestLayer
where
    S: tracing::Subscriber,
    S: for<'lookup> tracing_subscriber::registry::LookupSpan<'lookup>,
{
    fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
        let span = ctx.span(id).unwrap();
        let mut visitor = TestVisitor(None);
        attrs.record(&mut visitor);
        if let Some(test) = visitor.0 {
            span.extensions_mut().insert(Test(test));
        } else {
            // span has no test value
        }

        let parent = span.parent().unwrap();
        if let Some(Test(test)) = parent.extensions().get::<Test>() {
            // parent test value is `test`
        } else {
            // parent has no test value
        };
    }
}

然而,与访问者一起访问每个字段/值感觉好像我做错了什么,这是获取属性值的最佳方法吗?
据我所知,使用.record()是访问span值的唯一方法。

相关问题