rust_analyzer/tracing/
config.rs1use std::io::{self};
5
6use anyhow::Context;
7use tracing::level_filters::LevelFilter;
8use tracing_subscriber::{
9 Layer, Registry,
10 filter::{Targets, filter_fn},
11 fmt::{MakeWriter, time},
12 layer::SubscriberExt,
13};
14use tracing_tree::HierarchicalLayer;
15
16use crate::tracing::hprof;
17use crate::tracing::json;
18
19#[derive(Debug)]
20pub struct Config<T> {
21 pub writer: T,
22 pub filter: String,
23 pub chalk_filter: Option<String>,
33 pub profile_filter: Option<String>,
40
41 pub json_profile_filter: Option<String>,
46}
47
48impl<T> Config<T>
49where
50 T: for<'writer> MakeWriter<'writer> + Send + Sync + 'static,
51{
52 pub fn init(self) -> anyhow::Result<()> {
53 let targets_filter: Targets = self
54 .filter
55 .parse()
56 .with_context(|| format!("invalid log filter: `{}`", self.filter))?;
57
58 let writer = self.writer;
59
60 let ra_fmt_layer = tracing_subscriber::fmt::layer()
61 .with_target(false)
62 .with_ansi(false)
63 .with_writer(writer);
64
65 let ra_fmt_layer = match time::OffsetTime::local_rfc_3339() {
66 Ok(timer) => {
67 ra_fmt_layer.with_timer(timer).boxed()
69 }
70 Err(_) => {
71 ra_fmt_layer.boxed()
74 }
75 }
76 .with_filter(targets_filter);
77
78 let chalk_layer = match self.chalk_filter {
79 Some(chalk_filter) => {
80 let level: LevelFilter =
81 chalk_filter.parse().with_context(|| "invalid chalk log filter")?;
82
83 let chalk_filter = Targets::new()
84 .with_target("chalk_solve", level)
85 .with_target("chalk_ir", level)
86 .with_target("chalk_recursive", level);
87 HierarchicalLayer::default()
89 .with_indent_lines(true)
90 .with_ansi(false)
91 .with_indent_amount(2)
92 .with_writer(io::stderr)
93 .with_filter(chalk_filter)
94 .boxed()
95 }
96 None => None::<HierarchicalLayer>.with_filter(LevelFilter::OFF).boxed(),
97 };
98
99 let profiler_layer = match self.profile_filter {
101 Some(spec) => Some(hprof::SpanTree::new(&spec)).with_filter(LevelFilter::INFO),
102 None => None.with_filter(LevelFilter::OFF),
103 };
104
105 let json_profiler_layer = match self.json_profile_filter {
106 Some(spec) => {
107 let filter = json::JsonFilter::from_spec(&spec);
108 let filter = filter_fn(move |metadata| {
109 let allowed = match &filter.allowed_names {
110 Some(names) => names.contains(metadata.name()),
111 None => true,
112 };
113
114 allowed && metadata.is_span()
115 });
116 Some(json::TimingLayer::new(std::io::stderr).with_filter(filter))
117 }
118 None => None,
119 };
120
121 let subscriber = Registry::default()
122 .with(ra_fmt_layer)
123 .with(json_profiler_layer)
124 .with(profiler_layer)
125 .with(chalk_layer);
126
127 tracing::subscriber::set_global_default(subscriber)?;
128
129 Ok(())
130 }
131}