itrace 0.1.1

Structured, columnar tracing for Rust applications
Documentation
// Copyright (c) 2026 Claudio Carraro <wiclac@pm.me>
// SPDX-License-Identifier: BSD-3-Clause

use std::sync::Arc;

use arc_swap::ArcSwap;
use tracing_subscriber::prelude::*;
use tracing_subscriber::{EnvFilter, fmt};

use crate::config::Config;
use crate::error::ItraceError;
use crate::formatter::ItraceFormatter;

/// Builder per la configurazione e l'inizializzazione del subscriber itrace.
///
/// # Esempio
///
/// ```rust
/// itrace::builder()
///     .tracer("myapp")
///     .from_env()
///     .init()?;
/// ```
pub struct Builder {
    tracer_name: String,
    use_env: bool,
}

impl Default for Builder {
    fn default() -> Self {
        Self::new()
    }
}

impl Builder {
    pub fn new() -> Self {
        Self {
            tracer_name: "default".to_string(),
            use_env: false,
        }
    }

    /// Specifica il nome del file tracer da usare (senza estensione .toml).
    pub fn tracer(mut self, name: &str) -> Self {
        self.tracer_name = name.to_string();
        self
    }

    /// Se presente, la variabile d'ambiente ITRACE_TRACER sovrascrive
    /// il nome del tracer specificato con `.tracer()`.
    pub fn from_env(mut self) -> Self {
        self.use_env = true;
        self
    }

    /// Costruisce il subscriber e lo registra come subscriber globale.
    pub fn init(self) -> Result<(), ItraceError> {
        let tracer_name = self.resolve_tracer_name();
        let config = Config::load(&tracer_name)?;

        let filter_string = config.to_env_filter_string();
        let filter = EnvFilter::try_new(&filter_string).unwrap_or_else(|_| EnvFilter::new("info"));

        let shared = Arc::new(ArcSwap::new(Arc::new(config)));
        let formatter = ItraceFormatter::new(Arc::clone(&shared));

        let subscriber = tracing_subscriber::registry().with(filter).with(
            fmt::Layer::new()
                .event_format(formatter)
                .with_writer(std::io::stderr),
        );

        subscriber.try_init()?;

        Ok(())
    }

    fn resolve_tracer_name(&self) -> String {
        if self.use_env {
            std::env::var("ITRACE_TRACER").unwrap_or_else(|_| self.tracer_name.clone())
        } else {
            self.tracer_name.clone()
        }
    }
}