Skip to main content

folk_core/
logging.rs

1//! `tracing` initialization.
2//!
3//! Three formats supported:
4//! - `text` — compact, `[plugin]` prefix, single-line (default).
5//! - `json` — structured, one JSON object per line (for log aggregators).
6//! - `pretty` — multi-line human format (good for development).
7
8use anyhow::{Context, Result};
9use tracing_subscriber::{EnvFilter, fmt, prelude::*};
10
11use crate::config::{LogConfig, LogFormat};
12
13/// Initialize the global `tracing` subscriber.
14///
15/// Reads `RUST_LOG` first; if absent, uses `config.effective_filter()` which
16/// combines `config.filter` with per-plugin overrides from `[log.plugins]`.
17///
18/// Should be called exactly once at server startup. Calling twice is harmless
19/// but logs a warning.
20pub fn init(config: &LogConfig) -> Result<()> {
21    let filter = EnvFilter::try_from_default_env()
22        .unwrap_or_else(|_| EnvFilter::new(config.effective_filter()));
23
24    let registry = tracing_subscriber::registry().with(filter);
25
26    let result = match config.format {
27        LogFormat::Text => registry
28            .with(
29                fmt::layer()
30                    .with_target(true)
31                    .with_thread_ids(false)
32                    .with_thread_names(false),
33            )
34            .try_init(),
35        LogFormat::Json => registry
36            .with(fmt::layer().json().with_target(true).flatten_event(true))
37            .try_init(),
38        LogFormat::Pretty => registry.with(fmt::layer().pretty()).try_init(),
39    };
40
41    result.context("tracing subscriber already initialized")
42}