richat_shared/
tracing.rs

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}