use std::sync::{Arc, Mutex};
use tracing::instrument;
use tracing_subscriber::layer::SubscriberExt;
use tracing_wide::{
Message, event, message,
subscriber::{Subscriber, Subscribers},
};
struct Park(Arc<Mutex<Option<WorkFinished>>>);
#[message(msg = "work finished")]
#[derive(Clone, Default)]
struct WorkFinished {
attempt: Option<usize>,
component: Option<String>,
payload: usize,
}
impl WorkFinished {
fn payload(payload: usize) -> Self {
WorkFinished {
payload,
..Default::default()
}
}
}
impl Subscriber for Park {
fn on_message(&self, m: &dyn Message) {
if let Some(work) = m.as_any().downcast_ref::<WorkFinished>() {
*self.0.lock().unwrap() = Some(work.clone());
}
}
}
#[instrument(fields(component = "billing"))]
fn handle(attempt: usize) {
work(attempt);
}
#[instrument]
fn work(attempt: usize) {
event!(WorkFinished::payload(42));
}
fn main() {
let parked = Arc::new(Mutex::new(None));
let mut subscribers = Subscribers::default();
subscribers.register(Box::new(Park(parked.clone())));
subscribers.install().ok();
let subscriber = tracing_subscriber::registry()
.with(tracing_wide::instrument::layer())
.with(tracing_subscriber::fmt::layer().without_time());
tracing::subscriber::set_global_default(subscriber).expect("first subscriber");
handle(3);
let work = parked
.lock()
.unwrap()
.take()
.expect("the typed subscriber saw the event");
assert_eq!(work.payload, 42, "required field, from the literal");
assert_eq!(
work.component.as_deref(),
Some("billing"),
"joined from handle's explicit fields(...)"
);
assert_eq!(
work.attempt,
Some(3),
"joined from work's auto-recorded argument"
);
println!(
"[parked] all values present: payload={} component={:?} attempt={:?}",
work.payload, work.component, work.attempt
);
}