pub mod structured;
pub mod config;
pub mod wrapper;
pub mod middleware;
use log::{debug, error, info, trace, warn, LevelFilter};
use std::sync::Once;
use std::sync::atomic::{AtomicBool, Ordering};
use crate::logging::config::LoggingConfig;
use crate::logging::structured::{LoggerGuard, init_global_logger};
static INIT: Once = Once::new();
static USING_STRUCTURED: AtomicBool = AtomicBool::new(false);
static mut LOGGER_GUARD: Option<LoggerGuard> = None;
pub fn init_with_config(level: LevelFilter, config: &LoggingConfig) {
INIT.call_once(|| {
log::set_max_level(level);
if config.structured {
let logger_config = config.to_logger_config();
let guard = init_global_logger(&logger_config);
unsafe { LOGGER_GUARD = Some(guard); }
USING_STRUCTURED.store(true, Ordering::SeqCst);
} else {
let env = env_logger::Env::default().filter_or("RUST_LOG", level.as_str());
env_logger::Builder::from_env(env)
.format_timestamp_millis()
.format_target(true)
.init();
}
info!("Logging initialized at level: {}", log::max_level());
});
}
pub fn is_structured_logging() -> bool {
USING_STRUCTURED.load(Ordering::SeqCst)
}
pub fn log_error<E: std::fmt::Display>(context: &str, err: E) -> E {
if is_structured_logging() {
slog_scope::error!("{}", err; "context" => context);
} else {
error!("{}: {}", context, err);
}
err
}
pub fn log_warning<E: std::fmt::Display>(context: &str, err: E) {
if is_structured_logging() {
slog_scope::warn!("{}", err; "context" => context);
} else {
warn!("{}: {}", context, err);
}
}
pub fn log_debug<M: std::fmt::Display>(context: &str, msg: M) {
if is_structured_logging() {
slog_scope::debug!("{}", msg; "context" => context);
} else {
debug!("{}: {}", context, msg);
}
}
pub fn log_trace<M: std::fmt::Display>(context: &str, msg: M) {
if is_structured_logging() {
slog_scope::trace!("{}", msg; "context" => context);
} else {
trace!("{}: {}", context, msg);
}
}
pub fn log_info<M: std::fmt::Display>(context: &str, msg: M) {
if is_structured_logging() {
slog_scope::info!("{}", msg; "context" => context);
} else {
info!("{}: {}", context, msg);
}
}
pub fn log_with_context(
level: log::Level,
message: impl std::fmt::Display,
context: &str,
fields: &[(&'static str, String)]
) {
if is_structured_logging() {
match level {
log::Level::Error => {
let logger = slog_scope::logger();
let context_str = context.to_string(); let logger = logger.new(slog::o!("context" => context_str));
let logger = add_fields_to_logger(logger, fields);
slog::error!(logger, "{}", message);
},
log::Level::Warn => {
let logger = slog_scope::logger();
let context_str = context.to_string(); let logger = logger.new(slog::o!("context" => context_str));
let logger = add_fields_to_logger(logger, fields);
slog::warn!(logger, "{}", message);
},
log::Level::Info => {
let logger = slog_scope::logger();
let context_str = context.to_string(); let logger = logger.new(slog::o!("context" => context_str));
let logger = add_fields_to_logger(logger, fields);
slog::info!(logger, "{}", message);
},
log::Level::Debug => {
let logger = slog_scope::logger();
let context_str = context.to_string(); let logger = logger.new(slog::o!("context" => context_str));
let logger = add_fields_to_logger(logger, fields);
slog::debug!(logger, "{}", message);
},
log::Level::Trace => {
let logger = slog_scope::logger();
let context_str = context.to_string(); let logger = logger.new(slog::o!("context" => context_str));
let logger = add_fields_to_logger(logger, fields);
slog::trace!(logger, "{}", message);
},
}
} else {
match level {
log::Level::Error => crate::error!("{}: {}", context, message),
log::Level::Warn => crate::warn!("{}: {}", context, message),
log::Level::Info => crate::info!("{}: {}", context, message),
log::Level::Debug => crate::debug!("{}: {}", context, message),
log::Level::Trace => crate::trace!("{}: {}", context, message),
}
}
}
fn add_fields_to_logger(logger: slog::Logger, fields: &[(&'static str, String)]) -> slog::Logger {
let mut result = logger;
for (k, v) in fields {
let v_clone = v.clone(); result = result.new(slog::o!(*k => v_clone));
}
result
}