1pub mod config;
15pub mod middleware;
16pub mod structured;
17pub mod test_logger;
18pub mod wrapper;
19
20#[cfg(test)]
21#[path = "../../tests/unit/logging/tests.rs"]
22mod tests;
23
24use crate::logging::config::LoggingConfig;
25use crate::logging::structured::{LoggerGuard, init_global_logger};
26use log::{LevelFilter, debug, error, info, trace, warn};
27use std::sync::Once;
28use std::sync::atomic::{AtomicBool, Ordering};
29
30static INIT: Once = Once::new();
31static USING_STRUCTURED: AtomicBool = AtomicBool::new(false);
32static mut LOGGER_GUARD: Option<LoggerGuard> = None;
33
34pub fn init_with_config(level: LevelFilter, config: &LoggingConfig) {
38 INIT.call_once(|| {
39 log::set_max_level(level);
40
41 if config.structured {
42 let logger_config = config.to_logger_config();
43 let guard = init_global_logger(&logger_config);
44
45 unsafe {
47 LOGGER_GUARD = Some(guard);
48 }
49 USING_STRUCTURED.store(true, Ordering::SeqCst);
50 } else {
51 let env = env_logger::Env::default().filter_or("RUST_LOG", level.as_str());
54 env_logger::Builder::from_env(env)
55 .format_timestamp_millis()
56 .format_target(true)
57 .init();
58 }
59
60 info!("Logging initialized at level: {}", log::max_level());
61 });
62}
63
64pub fn is_structured_logging() -> bool {
66 USING_STRUCTURED.load(Ordering::SeqCst)
67}
68
69pub fn log_error<E: std::fmt::Display>(context: &str, err: E) -> E {
73 if is_structured_logging() {
74 slog_scope::error!("{}", err; "context" => context);
75 } else {
76 error!("{context}: {err}");
77 }
78 err
79}
80
81pub fn log_warning<E: std::fmt::Display>(context: &str, err: E) {
83 if is_structured_logging() {
84 slog_scope::warn!("{}", err; "context" => context);
85 } else {
86 warn!("{context}: {err}");
87 }
88}
89
90pub fn log_debug<M: std::fmt::Display>(context: &str, msg: M) {
92 if is_structured_logging() {
93 slog_scope::debug!("{}", msg; "context" => context);
94 } else {
95 debug!("{context}: {msg}");
96 }
97}
98
99pub fn log_trace<M: std::fmt::Display>(context: &str, msg: M) {
101 if is_structured_logging() {
102 slog_scope::trace!("{}", msg; "context" => context);
103 } else {
104 trace!("{context}: {msg}");
105 }
106}
107
108pub fn log_info<M: std::fmt::Display>(context: &str, msg: M) {
110 if is_structured_logging() {
111 slog_scope::info!("{}", msg; "context" => context);
112 } else {
113 info!("{context}: {msg}");
114 }
115}
116
117pub fn log_with_context(
119 level: log::Level,
120 message: impl std::fmt::Display,
121 context: &str,
122 fields: &[(&'static str, String)],
123) {
124 if is_structured_logging() {
125 match level {
126 log::Level::Error => {
127 let logger = slog_scope::logger();
128 let context_str = context.to_string(); let logger = logger.new(slog::o!("context" => context_str));
130 let logger = add_fields_to_logger(logger, fields);
131 slog::error!(logger, "{}", message);
132 }
133 log::Level::Warn => {
134 let logger = slog_scope::logger();
135 let context_str = context.to_string(); let logger = logger.new(slog::o!("context" => context_str));
137 let logger = add_fields_to_logger(logger, fields);
138 slog::warn!(logger, "{}", message);
139 }
140 log::Level::Info => {
141 let logger = slog_scope::logger();
142 let context_str = context.to_string(); let logger = logger.new(slog::o!("context" => context_str));
144 let logger = add_fields_to_logger(logger, fields);
145 slog::info!(logger, "{}", message);
146 }
147 log::Level::Debug => {
148 let logger = slog_scope::logger();
149 let context_str = context.to_string(); let logger = logger.new(slog::o!("context" => context_str));
151 let logger = add_fields_to_logger(logger, fields);
152 slog::debug!(logger, "{}", message);
153 }
154 log::Level::Trace => {
155 let logger = slog_scope::logger();
156 let context_str = context.to_string(); let logger = logger.new(slog::o!("context" => context_str));
158 let logger = add_fields_to_logger(logger, fields);
159 slog::trace!(logger, "{}", message);
160 }
161 }
162 } else {
163 match level {
165 log::Level::Error => crate::error!("{}: {}", context, message),
166 log::Level::Warn => crate::warn!("{}: {}", context, message),
167 log::Level::Info => crate::info!("{}: {}", context, message),
168 log::Level::Debug => crate::debug!("{}: {}", context, message),
169 log::Level::Trace => crate::trace!("{}: {}", context, message),
170 }
171 }
172}
173
174fn add_fields_to_logger(logger: slog::Logger, fields: &[(&'static str, String)]) -> slog::Logger {
176 let mut result = logger;
177 for (k, v) in fields {
178 let v_clone = v.clone(); result = result.new(slog::o!(*k => v_clone));
180 }
181 result
182}