rust_analyzer/tracing/
json.rs
1use std::{io::Write as _, marker::PhantomData, time::Instant};
12
13use ide_db::FxHashSet;
14use tracing::{
15 Event, Subscriber,
16 span::{Attributes, Id},
17};
18use tracing_subscriber::{Layer, fmt::MakeWriter, layer::Context, registry::LookupSpan};
19
20struct JsonData {
21 name: &'static str,
22 start: std::time::Instant,
23}
24
25impl JsonData {
26 fn new(name: &'static str) -> Self {
27 Self { name, start: Instant::now() }
28 }
29}
30
31#[derive(Debug)]
32pub(crate) struct TimingLayer<S, W> {
33 writer: W,
34 _inner: PhantomData<fn(S)>,
35}
36
37impl<S, W> TimingLayer<S, W> {
38 pub(crate) fn new(writer: W) -> Self {
39 Self { writer, _inner: PhantomData }
40 }
41}
42
43impl<S, W> Layer<S> for TimingLayer<S, W>
44where
45 S: Subscriber + for<'span> LookupSpan<'span>,
46 W: for<'writer> MakeWriter<'writer> + Send + Sync + 'static,
47{
48 fn on_new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
49 let span = ctx.span(id).unwrap();
50
51 let data = JsonData::new(attrs.metadata().name());
52 span.extensions_mut().insert(data);
53 }
54
55 fn on_event(&self, _event: &Event<'_>, _ctx: Context<'_, S>) {}
56
57 fn on_close(&self, id: Id, ctx: Context<'_, S>) {
58 #[derive(serde_derive::Serialize)]
59 struct JsonDataInner {
60 name: &'static str,
61 elapsed_ms: u128,
62 }
63
64 let span = ctx.span(&id).unwrap();
65 let Some(data) = span.extensions_mut().remove::<JsonData>() else {
66 return;
67 };
68
69 let data = JsonDataInner { name: data.name, elapsed_ms: data.start.elapsed().as_millis() };
70 let mut out = serde_json::to_string(&data).expect("Unable to serialize data");
71 out.push('\n');
72 self.writer.make_writer().write_all(out.as_bytes()).expect("Unable to write data");
73 }
74}
75
76#[derive(Default, Clone, Debug)]
77pub(crate) struct JsonFilter {
78 pub(crate) allowed_names: Option<FxHashSet<String>>,
79}
80
81impl JsonFilter {
82 pub(crate) fn from_spec(spec: &str) -> Self {
83 let allowed_names = if spec == "*" {
84 None
85 } else {
86 Some(FxHashSet::from_iter(spec.split('|').map(String::from)))
87 };
88
89 Self { allowed_names }
90 }
91}