Я пытаюсь настроить функцию с помощью трассировки tokio, получить ее аргументы, а затем перейти к родителю 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);
...
}
Кажется, это работает и позволяет мне получить ожидаемое attributes
span
. Однако при посещении каждого поля/значения посетителем кажется, что я делаю что-то не так. Это лучший способ получить значения атрибутов?
Отсюда я хотел бы получить два поля из родительского диапазона. Кажется, я должен быть в состоянии сделать что-то вроде:
let parent = span.parent().unwrap();
let parent_fields = p.fields();
// ... Read the data from the fields?
Однако, похоже, это не работает, поскольку fields()
предоставляет FieldSet
и не имеет явного доступа к значениям или ValueSet
. Как правильно получить значение из родительского поля? Есть ли более простой/лучший способ сделать это?
Атрибуты и, следовательно, содержащиеся в них значения доступны только при создании нового диапазона. Платформа трассировки не хранит их для проверки, что снижает накладные расходы. Именно подписчик отвечает за сохранение любых значений, которые ему нужны при обработке диапазонов.
К счастью, есть несколько инструментов, которые могут помочь. Вы уже пользуетесь экосистемой Layer от tracing-subscriber и даже полагаетесь на его Registry и черту LookupSpan . Реестр предоставляет механизм общего назначения для хранения данных с интервалами, выполняемыми с помощью Расширений.
Это означает, что ваш MyTestLayer
должен хранить любые данные, которые потребуются позже при обработке родительского диапазона, которые затем могут быть извлечены из реестра при обработке дочернего элемента.
Вот пример, который извлекает и сохраняет значение поля "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()
— единственный способ получить доступ к значениям диапазона.