#[macro_export]
macro_rules! log_trace {
($msg:literal, component = $component:expr) => {
log::trace!(component = $component; $msg);
};
($fmt:literal, $($args:expr),+, component = $component:expr) => {
log::trace!(component = $component; $fmt, $($args),+);
};
($msg:literal, color = $color:expr) => {
log::trace!(color = $color as u8; $msg);
};
($fmt:literal, $($args:expr),+, color = $color:expr) => {
log::trace!(color = $color as u8; $fmt, $($args),+);
};
($msg:literal, color = $color:expr, component = $component:expr) => {
log::trace!(component = $component, color = $color as u8; $msg);
};
($fmt:literal, $($args:expr),+, color = $color:expr, component = $component:expr) => {
log::trace!(component = $component, color = $color as u8; $fmt, $($args),+);
};
($msg:literal, component = $component:expr, color = $color:expr) => {
log::trace!(component = $component, color = $color as u8; $msg);
};
($fmt:literal, $($args:expr),+, component = $component:expr, color = $color:expr) => {
log::trace!(component = $component, color = $color as u8; $fmt, $($args),+);
};
($msg:literal) => {
log::trace!(component = module_path!(), color = $crate::enums::LogColor::Normal as u8; $msg);
};
($fmt:literal, $($args:expr),+) => {
log::trace!(component = module_path!(), color = $crate::enums::LogColor::Normal as u8; $fmt, $($args),+);
};
}
#[macro_export]
macro_rules! log_debug {
($msg:literal, component = $component:expr) => {
log::debug!(component = $component; $msg);
};
($fmt:literal, $($args:expr),+, component = $component:expr) => {
log::debug!(component = $component; $fmt, $($args),+);
};
($msg:literal, color = $color:expr) => {
log::debug!(color = $color as u8; $msg);
};
($fmt:literal, $($args:expr),+, color = $color:expr) => {
log::debug!(color = $color as u8; $fmt, $($args),+);
};
($msg:literal, color = $color:expr, component = $component:expr) => {
log::debug!(component = $component, color = $color as u8; $msg);
};
($fmt:literal, $($args:expr),+, color = $color:expr, component = $component:expr) => {
log::debug!(component = $component, color = $color as u8; $fmt, $($args),+);
};
($msg:literal, component = $component:expr, color = $color:expr) => {
log::debug!(component = $component, color = $color as u8; $msg);
};
($fmt:literal, $($args:expr),+, component = $component:expr, color = $color:expr) => {
log::debug!(component = $component, color = $color as u8; $fmt, $($args),+);
};
($msg:literal) => {
log::debug!(component = module_path!(), color = $crate::enums::LogColor::Normal as u8; $msg);
};
($fmt:literal, $($args:expr),+) => {
log::debug!(component = module_path!(), color = $crate::enums::LogColor::Normal as u8; $fmt, $($args),+);
};
}
#[macro_export]
macro_rules! log_info {
($msg:literal, color = $color:expr, component = $component:expr) => {
log::info!(component = $component, color = $color as u8; $msg);
};
($fmt:literal, $arg1:expr, color = $color:expr, component = $component:expr) => {
log::info!(component = $component, color = $color as u8; $fmt, $arg1);
};
($fmt:literal, $arg1:expr, $arg2:expr, color = $color:expr, component = $component:expr) => {
log::info!(component = $component, color = $color as u8; $fmt, $arg1, $arg2);
};
($msg:literal, component = $component:expr, color = $color:expr) => {
log::info!(component = $component, color = $color as u8; $msg);
};
($fmt:literal, $arg1:expr, component = $component:expr, color = $color:expr) => {
log::info!(component = $component, color = $color as u8; $fmt, $arg1);
};
($fmt:literal, $arg1:expr, $arg2:expr, component = $component:expr, color = $color:expr) => {
log::info!(component = $component, color = $color as u8; $fmt, $arg1, $arg2);
};
($msg:literal, component = $component:expr) => {
log::info!(component = $component; $msg);
};
($fmt:literal, $arg1:expr, component = $component:expr) => {
log::info!(component = $component; $fmt, $arg1);
};
($fmt:literal, $arg1:expr, $arg2:expr, component = $component:expr) => {
log::info!(component = $component; $fmt, $arg1, $arg2);
};
($msg:literal, color = $color:expr) => {
log::info!(color = $color as u8; $msg);
};
($fmt:literal, $arg1:expr, color = $color:expr) => {
log::info!(color = $color as u8; $fmt, $arg1);
};
($fmt:literal, $arg1:expr, $arg2:expr, color = $color:expr) => {
log::info!(color = $color as u8; $fmt, $arg1, $arg2);
};
($fmt:literal, $arg1:expr, $arg2:expr, $arg3:expr, color = $color:expr) => {
log::info!(color = $color as u8; $fmt, $arg1, $arg2, $arg3);
};
($msg:literal) => {
log::info!(component = module_path!(), color = $crate::enums::LogColor::Normal as u8; $msg);
};
($fmt:literal, $($args:expr),+) => {
log::info!(component = module_path!(), color = $crate::enums::LogColor::Normal as u8; $fmt, $($args),+);
};
}
#[macro_export]
macro_rules! log_warn {
($msg:literal, color = $color:expr, component = $component:expr) => {
log::warn!(component = $component, color = $color as u8; $msg);
};
($fmt:literal, $arg1:expr, color = $color:expr, component = $component:expr) => {
log::warn!(component = $component, color = $color as u8; $fmt, $arg1);
};
($fmt:literal, $arg1:expr, $arg2:expr, color = $color:expr, component = $component:expr) => {
log::warn!(component = $component, color = $color as u8; $fmt, $arg1, $arg2);
};
($msg:literal, component = $component:expr, color = $color:expr) => {
log::warn!(component = $component, color = $color as u8; $msg);
};
($fmt:literal, $arg1:expr, component = $component:expr, color = $color:expr) => {
log::warn!(component = $component, color = $color as u8; $fmt, $arg1);
};
($fmt:literal, $arg1:expr, $arg2:expr, component = $component:expr, color = $color:expr) => {
log::warn!(component = $component, color = $color as u8; $fmt, $arg1, $arg2);
};
($msg:literal, component = $component:expr) => {
log::warn!(component = $component, color = $crate::enums::LogColor::Yellow as u8; $msg);
};
($fmt:literal, $arg1:expr, component = $component:expr) => {
log::warn!(component = $component, color = $crate::enums::LogColor::Yellow as u8; $fmt, $arg1);
};
($fmt:literal, $arg1:expr, $arg2:expr, component = $component:expr) => {
log::warn!(component = $component, color = $crate::enums::LogColor::Yellow as u8; $fmt, $arg1, $arg2);
};
($msg:literal, color = $color:expr) => {
log::warn!(color = $color as u8; $msg);
};
($fmt:literal, $arg1:expr, color = $color:expr) => {
log::warn!(color = $color as u8; $fmt, $arg1);
};
($fmt:literal, $arg1:expr, $arg2:expr, color = $color:expr) => {
log::warn!(color = $color as u8; $fmt, $arg1, $arg2);
};
($fmt:literal, $arg1:expr, $arg2:expr, $arg3:expr, color = $color:expr) => {
log::warn!(color = $color as u8; $fmt, $arg1, $arg2, $arg3);
};
($msg:literal) => {
log::warn!(component = module_path!(), color = $crate::enums::LogColor::Yellow as u8; $msg);
};
($fmt:literal, $($args:expr),+) => {
log::warn!(component = module_path!(), color = $crate::enums::LogColor::Yellow as u8; $fmt, $($args),+);
};
}
#[macro_export]
macro_rules! log_error {
($msg:literal, color = $color:expr, component = $component:expr) => {
log::error!(component = $component, color = $color as u8; $msg);
};
($fmt:literal, $arg1:expr, color = $color:expr, component = $component:expr) => {
log::error!(component = $component, color = $color as u8; $fmt, $arg1);
};
($fmt:literal, $arg1:expr, $arg2:expr, color = $color:expr, component = $component:expr) => {
log::error!(component = $component, color = $color as u8; $fmt, $arg1, $arg2);
};
($msg:literal, component = $component:expr, color = $color:expr) => {
log::error!(component = $component, color = $color as u8; $msg);
};
($fmt:literal, $arg1:expr, component = $component:expr, color = $color:expr) => {
log::error!(component = $component, color = $color as u8; $fmt, $arg1);
};
($fmt:literal, $arg1:expr, $arg2:expr, component = $component:expr, color = $color:expr) => {
log::error!(component = $component, color = $color as u8; $fmt, $arg1, $arg2);
};
($msg:literal, component = $component:expr) => {
log::error!(component = $component, color = $crate::enums::LogColor::Red as u8; $msg);
};
($fmt:literal, $arg1:expr, component = $component:expr) => {
log::error!(component = $component, color = $crate::enums::LogColor::Red as u8; $fmt, $arg1);
};
($fmt:literal, $arg1:expr, $arg2:expr, component = $component:expr) => {
log::error!(component = $component, color = $crate::enums::LogColor::Red as u8; $fmt, $arg1, $arg2);
};
($msg:literal, color = $color:expr) => {
log::error!(color = $color as u8; $msg);
};
($fmt:literal, $arg1:expr, color = $color:expr) => {
log::error!(color = $color as u8; $fmt, $arg1);
};
($fmt:literal, $arg1:expr, $arg2:expr, color = $color:expr) => {
log::error!(color = $color as u8; $fmt, $arg1, $arg2);
};
($fmt:literal, $arg1:expr, $arg2:expr, $arg3:expr, color = $color:expr) => {
log::error!(color = $color as u8; $fmt, $arg1, $arg2, $arg3);
};
($msg:literal) => {
log::error!(component = module_path!(), color = $crate::enums::LogColor::Red as u8; $msg);
};
($fmt:literal, $($args:expr),+) => {
log::error!(component = module_path!(), color = $crate::enums::LogColor::Red as u8; $fmt, $($args),+);
};
}
pub use log_debug;
pub use log_error;
pub use log_info;
pub use log_trace;
pub use log_warn;
#[cfg(all(test, not(all(feature = "simulation", madsim))))]
mod tests {
use std::{thread::sleep, time::Duration};
use nautilus_core::UUID4;
use nautilus_model::identifiers::TraderId;
use rstest::*;
use tempfile::tempdir;
use crate::{
enums::LogColor,
logging::{
logger::{Logger, LoggerConfig},
logging_clock_set_static_mode, logging_clock_set_static_time,
writer::FileWriterConfig,
},
testing::wait_until,
};
#[rstest]
fn test_colored_logging_macros() {
let config = LoggerConfig::from_spec("stdout=Trace;fileout=Trace;is_colored").unwrap();
let temp_dir = tempdir().expect("Failed to create temporary directory");
let file_config = FileWriterConfig {
directory: Some(temp_dir.path().to_str().unwrap().to_string()),
..Default::default()
};
let log_guard = Logger::init_with_config(
TraderId::from("TRADER-001"),
UUID4::new(),
config,
file_config,
)
.expect("Failed to initialize logger");
logging_clock_set_static_mode();
logging_clock_set_static_time(1_650_000_000_000_000);
log_trace!("This is a trace message", component = "TestComponent");
log_debug!("This is a debug message", component = "TestComponent");
log_info!("This is an info message", component = "TestComponent");
log_warn!("This is a warning message", component = "TestComponent");
log_error!("This is an error message", component = "TestComponent");
log_info!(
"Success message",
color = LogColor::Green,
component = "TestComponent"
);
log_info!(
"Information message",
color = LogColor::Blue,
component = "TestComponent"
);
log_warn!(
"Custom warning",
component = "TestComponent",
color = LogColor::Magenta
);
log_info!("Component test", component = "TestComponent");
log_warn!("Component warning", component = "TestComponent");
log_info!(
"Color then component",
color = LogColor::Cyan,
component = "TestComponent"
);
sleep(Duration::from_millis(200));
drop(log_guard);
let mut log_contents = String::new();
wait_until(
|| {
if let Some(log_file) = std::fs::read_dir(&temp_dir)
.expect("Failed to read directory")
.filter_map(Result::ok)
.find(|entry| entry.path().is_file())
{
let log_file_path = log_file.path();
log_contents =
std::fs::read_to_string(log_file_path).expect("Failed to read log file");
!log_contents.is_empty()
} else {
false
}
},
Duration::from_secs(3),
);
if !log_contents.contains("This is a trace message") {
println!("File contents:\n{log_contents}");
}
assert!(log_contents.contains("This is a trace message"));
assert!(log_contents.contains("This is a debug message"));
assert!(log_contents.contains("This is an info message"));
assert!(log_contents.contains("This is a warning message"));
assert!(log_contents.contains("This is an error message"));
assert!(log_contents.contains("Success message"));
assert!(log_contents.contains("Information message"));
assert!(log_contents.contains("Custom warning"));
assert!(log_contents.contains("Component test"));
assert!(log_contents.contains("Component warning"));
assert!(log_contents.contains("Color then component"));
}
#[rstest]
fn test_default_macro_captures_module_path() {
let config = LoggerConfig::from_spec(
"stdout=Off;fileout=Trace;nautilus_common::logging::macros=Debug",
)
.unwrap();
let temp_dir = tempdir().expect("Failed to create temporary directory");
let file_config = FileWriterConfig {
directory: Some(temp_dir.path().to_str().unwrap().to_string()),
..Default::default()
};
let log_guard = Logger::init_with_config(
TraderId::from("TRADER-PATH"),
UUID4::new(),
config,
file_config,
)
.expect("Failed to initialize logger");
logging_clock_set_static_mode();
logging_clock_set_static_time(1_650_000_000_000_000);
log_info!("Auto-captured module path message");
log_debug!("Debug level auto-captured");
log_trace!("Trace should be filtered SHOULD_NOT_APPEAR");
sleep(Duration::from_millis(200));
drop(log_guard);
let mut log_contents = String::new();
wait_until(
|| {
if let Some(log_file) = std::fs::read_dir(&temp_dir)
.expect("Failed to read directory")
.filter_map(Result::ok)
.find(|entry| entry.path().is_file())
{
log_contents =
std::fs::read_to_string(log_file.path()).expect("Failed to read log file");
!log_contents.is_empty()
} else {
false
}
},
Duration::from_secs(3),
);
assert!(
log_contents.contains("nautilus_common::logging::macros"),
"Component should contain module path, was:\n{log_contents}"
);
assert!(
log_contents.contains("Auto-captured module path message"),
"Info message should pass"
);
assert!(
log_contents.contains("Debug level auto-captured"),
"Debug message should pass"
);
assert!(
!log_contents.contains("SHOULD_NOT_APPEAR"),
"Trace should be filtered by module filter"
);
}
}