1use {
2 serde::Deserialize,
3 std::io::{self, IsTerminal},
4 thiserror::Error,
5 tracing::Subscriber,
6 tracing_subscriber::{
7 filter::{EnvFilter, FromEnvError, LevelFilter},
8 fmt::layer,
9 layer::{Layer, SubscriberExt},
10 registry::LookupSpan,
11 util::{SubscriberInitExt, TryInitError},
12 },
13};
14
15#[derive(Debug, Default, Clone, Deserialize)]
16#[serde(deny_unknown_fields, default)]
17pub struct ConfigTracing {
18 pub json: bool,
19}
20
21#[derive(Debug, Error)]
22pub enum TracingSetupError {
23 #[error(transparent)]
24 FromEnv(#[from] FromEnvError),
25 #[error(transparent)]
26 Init(#[from] TryInitError),
27}
28
29pub fn setup(json: bool) -> Result<(), TracingSetupError> {
30 let env = EnvFilter::builder()
31 .with_default_directive(LevelFilter::INFO.into())
32 .from_env()?;
33
34 tracing_subscriber::registry()
35 .with(env)
36 .with(create_io_layer(json))
37 .try_init()?;
38
39 Ok(())
40}
41
42fn create_io_layer<S>(json: bool) -> Box<dyn Layer<S> + Send + Sync + 'static>
43where
44 S: Subscriber,
45 for<'a> S: LookupSpan<'a>,
46{
47 let is_atty = io::stdout().is_terminal() && io::stderr().is_terminal();
48 let io_layer = layer().with_ansi(is_atty).with_line_number(true);
49
50 if json {
51 Box::new(io_layer.json())
52 } else {
53 Box::new(io_layer)
54 }
55}