use crate::errors::PriceLevelError;
use std::sync::OnceLock;
use tracing_subscriber::FmtSubscriber;
use {std::env, tracing::Level};
#[allow(dead_code)]
static LOGGER_INIT_RESULT: OnceLock<Result<(), String>> = OnceLock::new();
#[allow(dead_code)]
pub fn setup_logger() -> Result<(), PriceLevelError> {
let result = LOGGER_INIT_RESULT.get_or_init(|| {
let log_level = env::var("LOGLEVEL")
.unwrap_or_else(|_| "INFO".to_string())
.to_uppercase();
let level = match log_level.as_str() {
"DEBUG" => Level::DEBUG,
"ERROR" => Level::ERROR,
"WARN" => Level::WARN,
"TRACE" => Level::TRACE,
_ => Level::INFO,
};
let subscriber = FmtSubscriber::builder().with_max_level(level).finish();
tracing::subscriber::set_global_default(subscriber)
.map_err(|error| format!("failed to set global logging subscriber: {error}"))?;
tracing::debug!("Log level set to: {}", level);
Ok(())
});
result
.clone()
.map_err(|message| PriceLevelError::InvalidOperation { message })
}
#[cfg(test)]
mod tests_setup_logger {
use super::setup_logger;
use std::env;
use tracing::subscriber::set_global_default;
use tracing_subscriber::FmtSubscriber;
#[test]
fn test_logger_initialization_info() {
unsafe {
env::set_var("LOGLEVEL", "INFO");
}
assert!(setup_logger().is_ok());
assert!(
set_global_default(FmtSubscriber::builder().finish()).is_err(),
"Logger should already be set"
);
}
#[test]
fn test_logger_initialization_debug() {
unsafe {
env::set_var("LOGLEVEL", "DEBUG");
}
assert!(setup_logger().is_ok());
assert!(
set_global_default(FmtSubscriber::builder().finish()).is_err(),
"Logger should already be set"
);
}
#[test]
fn test_logger_initialization_default() {
unsafe {
env::remove_var("LOGLEVEL");
}
assert!(setup_logger().is_ok());
assert!(
set_global_default(FmtSubscriber::builder().finish()).is_err(),
"Logger should already be set"
);
}
#[test]
fn test_logger_called_once() {
unsafe {
env::set_var("LOGLEVEL", "INFO");
}
assert!(setup_logger().is_ok()); assert!(setup_logger().is_ok());
assert!(
set_global_default(FmtSubscriber::builder().finish()).is_err(),
"Logger should already be set and should not be reset"
);
}
}
#[cfg(test)]
mod tests_setup_logger_bis {
use super::*;
use std::sync::Mutex;
use tracing::subscriber::with_default;
use tracing_subscriber::Layer;
use tracing_subscriber::layer::{Context, SubscriberExt};
use tracing_subscriber::registry;
static TEST_MUTEX: Mutex<()> = Mutex::new(());
#[derive(Clone)]
struct TestLayer {
level: std::sync::Arc<Mutex<Option<Level>>>,
}
impl<S> Layer<S> for TestLayer
where
S: tracing::Subscriber,
{
fn on_event(&self, event: &tracing::Event<'_>, _ctx: Context<'_, S>) {
let mut level = self.level.lock().unwrap();
*level = Some(*event.metadata().level());
}
}
fn create_test_layer() -> (TestLayer, std::sync::Arc<Mutex<Option<Level>>>) {
let level = std::sync::Arc::new(Mutex::new(None));
(
TestLayer {
level: level.clone(),
},
level,
)
}
#[test]
fn test_default_log_level() {
let _lock = TEST_MUTEX.lock().unwrap();
unsafe {
env::remove_var("LOGLEVEL");
}
let (layer, level) = create_test_layer();
let subscriber = registry().with(layer);
with_default(subscriber, || {
assert!(setup_logger().is_ok());
tracing::info!("Test log");
});
assert_eq!(*level.lock().unwrap(), Some(Level::INFO));
}
#[test]
fn test_debug_log_level() {
let _lock = TEST_MUTEX.lock().unwrap();
unsafe {
env::set_var("LOGLEVEL", "DEBUG");
}
let (layer, level) = create_test_layer();
let subscriber = registry().with(layer);
with_default(subscriber, || {
assert!(setup_logger().is_ok());
tracing::debug!("Test log");
});
assert_eq!(*level.lock().unwrap(), Some(Level::DEBUG));
unsafe {
env::remove_var("LOGLEVEL");
}
}
#[test]
fn test_error_log_level() {
let _lock = TEST_MUTEX.lock().unwrap();
unsafe {
env::set_var("LOGLEVEL", "ERROR");
}
let (layer, level) = create_test_layer();
let subscriber = registry().with(layer);
with_default(subscriber, || {
assert!(setup_logger().is_ok());
tracing::error!("Test log");
});
assert_eq!(*level.lock().unwrap(), Some(Level::ERROR));
unsafe {
env::remove_var("LOGLEVEL");
}
}
#[test]
fn test_warn_log_level() {
let _lock = TEST_MUTEX.lock().unwrap();
unsafe {
env::set_var("LOGLEVEL", "WARN");
}
let (layer, level) = create_test_layer();
let subscriber = registry().with(layer);
with_default(subscriber, || {
assert!(setup_logger().is_ok());
tracing::warn!("Test log");
});
assert_eq!(*level.lock().unwrap(), Some(Level::WARN));
unsafe {
env::remove_var("LOGLEVEL");
}
}
#[test]
fn test_trace_log_level() {
let _lock = TEST_MUTEX.lock().unwrap();
unsafe {
env::set_var("LOGLEVEL", "TRACE");
}
let (layer, level) = create_test_layer();
let subscriber = registry().with(layer);
with_default(subscriber, || {
assert!(setup_logger().is_ok());
tracing::trace!("Test log");
});
assert_eq!(*level.lock().unwrap(), Some(Level::TRACE));
unsafe {
env::remove_var("LOGLEVEL");
}
}
#[test]
fn test_invalid_log_level() {
let _lock = TEST_MUTEX.lock().unwrap();
unsafe {
env::set_var("LOGLEVEL", "INVALID");
}
let (layer, level) = create_test_layer();
let subscriber = registry().with(layer);
with_default(subscriber, || {
assert!(setup_logger().is_ok());
tracing::info!("Test log");
});
assert_eq!(*level.lock().unwrap(), Some(Level::INFO));
unsafe {
env::remove_var("LOGLEVEL");
}
}
}