Initialize the tracing subscriber with an optional critical-event file layer. Replicates the stdout logging behavior of `commonware_runtime::tokio::telemetry::init` and adds an additional file layer filtered to `target: "critical"` events. Returns a guard that MUST be held for the process lifetime to ensure buffered critical events are flushed on shutdown.
(level: Level, critical_log_dir: Option<&Path>)
| 25 | /// Returns a guard that MUST be held for the process lifetime to ensure |
| 26 | /// buffered critical events are flushed on shutdown. |
| 27 | pub fn init(level: Level, critical_log_dir: Option<&Path>) -> CriticalLogGuard { |
| 28 | let env_filter = tracing_subscriber::EnvFilter::try_from_default_env() |
| 29 | .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new(level.to_string())); |
| 30 | |
| 31 | // Stdout fmt layer — same config as commonware telemetry::init |
| 32 | let stdout_layer = fmt::layer() |
| 33 | .with_line_number(true) |
| 34 | .with_thread_ids(true) |
| 35 | .with_file(true) |
| 36 | .with_span_events(fmt::format::FmtSpan::CLOSE) |
| 37 | .compact(); |
| 38 | |
| 39 | // Critical file layer (optional) |
| 40 | let (file_layer, guard) = if let Some(dir) = critical_log_dir { |
| 41 | let appender = LogRollerBuilder::new(dir, Path::new("critical.log")) |
| 42 | .rotation(Rotation::SizeBased(RotationSize::MB(100))) |
| 43 | .max_keep_files(5) |
| 44 | .build() |
| 45 | .expect("Failed to create critical log appender"); |
| 46 | |
| 47 | let (non_blocking, guard) = tracing_appender::non_blocking(appender); |
| 48 | |
| 49 | let layer = fmt::layer() |
| 50 | .with_writer(non_blocking) |
| 51 | .with_ansi(false) |
| 52 | .with_line_number(true) |
| 53 | .with_file(true) |
| 54 | .with_thread_ids(true) |
| 55 | .json() |
| 56 | .with_filter(filter::Targets::new().with_target("critical", Level::ERROR)) |
| 57 | .boxed(); |
| 58 | |
| 59 | (Some(layer), Some(guard)) |
| 60 | } else { |
| 61 | (None, None) |
| 62 | }; |
| 63 | |
| 64 | // Use try_init so callers that already have a global subscriber (e.g. testnet |
| 65 | // spawning multiple nodes in one process) don't panic. |
| 66 | let _ = Registry::default() |
| 67 | .with(env_filter) |
| 68 | .with(stdout_layer) |
| 69 | .with(file_layer) |
| 70 | .try_init(); |
| 71 | |
| 72 | CriticalLogGuard { _guard: guard } |
| 73 | } |