use crate::common;
use std::sync::{Arc, Mutex};
use tracing::field::{Field, Visit};
use tracing_subscriber::layer::{Context, SubscriberExt};
const SPAWNED_EVENT_MARKER: &str = "recorder-spawn-capture: event fired from a spawned task";
#[derive(Default, Clone)]
struct Recorded(Arc<Mutex<Vec<String>>>);
struct Recorder(Recorded);
impl<S: tracing::Subscriber> tracing_subscriber::Layer<S> for Recorder {
fn on_event(&self, event: &tracing::Event<'_>, _ctx: Context<'_, S>) {
struct MessageVisitor(String);
impl Visit for MessageVisitor {
fn record_debug(&mut self, field: &Field, value: &dyn std::fmt::Debug) {
if field.name() == "message" {
self.0 = format!("{value:?}");
}
}
}
let mut visitor = MessageVisitor(String::new());
event.record(&mut visitor);
self.0.0.lock().unwrap().push(visitor.0);
}
}
fn a_spawned_tasks_event_is_captured_through_with_recorder_dispatch() {
let recorded = Recorded::default();
let subscriber = tracing_subscriber::registry().with(Recorder(recorded.clone()));
common::with_recorder_dispatch(subscriber, async {
let handle = tokio::spawn(async {
tracing::info!("{SPAWNED_EVENT_MARKER}");
});
handle.await.expect("spawned task joins");
});
let messages = recorded.0.lock().unwrap().clone();
assert!(
messages.iter().any(|m| m.contains(SPAWNED_EVENT_MARKER)),
"expected the spawned task's event in the transcript; got {messages:?}"
);
}
pub(crate) fn recorder_trials(_rt: &'static tokio::runtime::Runtime) -> Vec<libtest_mimic::Trial> {
vec![libtest_mimic::Trial::test(
"recorder_spawn_capture::a_spawned_tasks_event_is_captured_through_with_recorder_dispatch",
|| {
a_spawned_tasks_event_is_captured_through_with_recorder_dispatch();
Ok(())
},
)]
}