1use opentelemetry::KeyValue;
29use opentelemetry_otlp::WithExportConfig;
30use opentelemetry_sdk::trace::{self, Sampler};
31use opentelemetry_sdk::Resource;
32use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry};
33use ferrox_errors::AppError;
34
35pub mod sanitizer;
36pub mod dp;
37pub mod weekly_report;
38pub mod merkle;
39pub mod merkle_audit_chain;
40pub use merkle_audit_chain::{AuditLogRecord, MerkleAuditChain};
41
42#[derive(Clone, serde::Deserialize)]
43pub struct LoggerConfig {
44 pub service_name: String,
45 pub environment: String,
46 pub otlp_endpoint: Option<String>,
47 pub sentry_dsn: Option<String>,
48 pub log_level: String,
49}
50
51impl Default for LoggerConfig {
52 fn default() -> Self {
53 Self {
54 service_name: "ferrox-app".to_string(),
55 environment: "development".to_string(),
56 otlp_endpoint: None,
57 sentry_dsn: None,
58 log_level: "info".to_string(),
59 }
60 }
61}
62
63pub fn setup_logger(config: LoggerConfig) -> Result<Option<sentry::ClientInitGuard>, AppError> {
64 let env_filter = EnvFilter::try_from_default_env()
65 .unwrap_or_else(|_| EnvFilter::new(&config.log_level));
66
67 let formatting_layer = tracing_subscriber::fmt::layer()
69 .json()
70 .with_file(true)
71 .with_line_number(true)
72 .with_target(false);
73
74 let subscriber = Registry::default().with(env_filter).with(formatting_layer);
75
76 let mut sentry_guard = None;
78 if let Some(dsn) = config.sentry_dsn {
79 sentry_guard = Some(sentry::init((
80 dsn,
81 sentry::ClientOptions {
82 release: sentry::release_name!(),
83 traces_sample_rate: 1.0,
84 environment: Some(config.environment.into()),
85 ..Default::default()
86 },
87 )));
88 }
89
90 let _ = subscriber.try_init();
91
92 tracing::info!("ferrox-logger initialized: Structured JSON logging enabled for service '{}'.", config.service_name);
93 Ok(sentry_guard)
94}