linker_diff/
diagnostics.rs1use std::cell::RefCell;
9use std::fmt::Write as _;
10use tracing_subscriber::layer::SubscriberExt as _;
11
12pub fn enable_diagnostics() {
15 let layer = TraceLayer;
16 let subscriber = tracing_subscriber::Registry::default().with(layer);
17 tracing::subscriber::set_global_default(subscriber)
18 .expect("Only one global tracing subscriber can be setup");
19}
20
21#[derive(Default, Debug, Clone)]
22pub(crate) struct TraceOutput {
23 pub(crate) messages: Vec<String>,
24}
25
26impl TraceOutput {
27 pub(crate) fn append(&mut self, mut other: TraceOutput) {
28 self.messages.append(&mut other.messages);
29 }
30}
31
32thread_local! {
33 pub static TRACE_STACK: RefCell<Vec<TraceOutput>> = const { RefCell::new(Vec::new()) };
34}
35
36pub(crate) fn trace_scope<T>(trace_output: &mut TraceOutput, f: impl FnOnce() -> T) -> T {
38 TRACE_STACK.with_borrow_mut(|stack| stack.push(TraceOutput::default()));
39
40 let result = f();
41
42 *trace_output = TRACE_STACK.with_borrow_mut(|stack| stack.pop()).unwrap();
43
44 result
45}
46
47struct TraceLayer;
48
49impl<S> tracing_subscriber::Layer<S> for TraceLayer
50where
51 S: tracing::Subscriber + for<'span> tracing_subscriber::registry::LookupSpan<'span>,
52{
53 fn on_event(
54 &self,
55 event: &tracing::Event<'_>,
56 _ctx: tracing_subscriber::layer::Context<'_, S>,
57 ) {
58 if TRACE_STACK.with_borrow(|stack| stack.is_empty()) {
59 return;
60 }
61
62 let mut formatter = MessageFormatter::default();
63 event.record(&mut formatter);
64
65 TRACE_STACK.with_borrow_mut(|stack| {
66 if let Some(out) = stack.last_mut() {
67 out.messages.push(formatter.out);
68 }
69 });
70 }
71}
72
73#[derive(Default)]
74struct MessageFormatter {
75 out: String,
76}
77
78impl tracing::field::Visit for MessageFormatter {
79 fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
80 if !self.out.is_empty() {
81 self.out.push(' ');
82 }
83 let _ = write!(&mut self.out, "{field}={value:?}");
84 }
85}