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
42pub struct LoggerConfig {
43 pub service_name: String,
44 pub environment: String,
45 pub otlp_endpoint: Option<String>,
46 pub sentry_dsn: Option<String>,
47 pub log_level: String,
48}
49
50impl Default for LoggerConfig {
51 fn default() -> Self {
52 Self {
53 service_name: "ferrox-app".to_string(),
54 environment: "development".to_string(),
55 otlp_endpoint: None,
56 sentry_dsn: None,
57 log_level: "info".to_string(),
58 }
59 }
60}
61
62pub fn setup_logger(config: LoggerConfig) -> Result<Option<sentry::ClientInitGuard>, AppError> {
63 let env_filter = EnvFilter::try_from_default_env()
64 .unwrap_or_else(|_| EnvFilter::new(&config.log_level));
65
66 let formatting_layer = tracing_subscriber::fmt::layer()
68 .json()
69 .with_file(true)
70 .with_line_number(true)
71 .with_target(false);
72
73 let subscriber = Registry::default().with(env_filter).with(formatting_layer);
74
75 let mut sentry_guard = None;
77 if let Some(dsn) = config.sentry_dsn {
78 sentry_guard = Some(sentry::init((
79 dsn,
80 sentry::ClientOptions {
81 release: sentry::release_name!(),
82 traces_sample_rate: 1.0,
83 environment: Some(config.environment.into()),
84 ..Default::default()
85 },
86 )));
87 }
88
89 let _ = subscriber.try_init();
90
91 tracing::info!("ferrox-logger initialized: Structured JSON logging enabled for service '{}'.", config.service_name);
92 Ok(sentry_guard)
93}