1#[macro_export]
36macro_rules! log_trace {
37 ($msg:literal, component = $component:expr) => {
39 log::trace!(component = $component; $msg);
40 };
41 ($fmt:literal, $($args:expr),+, component = $component:expr) => {
42 log::trace!(component = $component; $fmt, $($args),+);
43 };
44
45 ($msg:literal, color = $color:expr) => {
47 log::trace!(color = $color as u8; $msg);
48 };
49 ($fmt:literal, $($args:expr),+, color = $color:expr) => {
50 log::trace!(color = $color as u8; $fmt, $($args),+);
51 };
52
53 ($msg:literal, color = $color:expr, component = $component:expr) => {
55 log::trace!(component = $component, color = $color as u8; $msg);
56 };
57 ($fmt:literal, $($args:expr),+, color = $color:expr, component = $component:expr) => {
58 log::trace!(component = $component, color = $color as u8; $fmt, $($args),+);
59 };
60
61 ($msg:literal, component = $component:expr, color = $color:expr) => {
63 log::trace!(component = $component, color = $color as u8; $msg);
64 };
65 ($fmt:literal, $($args:expr),+, component = $component:expr, color = $color:expr) => {
66 log::trace!(component = $component, color = $color as u8; $fmt, $($args),+);
67 };
68
69 ($msg:literal) => {
71 log::trace!(component = module_path!(), color = $crate::enums::LogColor::Normal as u8; $msg);
72 };
73 ($fmt:literal, $($args:expr),+) => {
74 log::trace!(component = module_path!(), color = $crate::enums::LogColor::Normal as u8; $fmt, $($args),+);
75 };
76}
77
78#[macro_export]
96macro_rules! log_debug {
97 ($msg:literal, component = $component:expr) => {
99 log::debug!(component = $component; $msg);
100 };
101 ($fmt:literal, $($args:expr),+, component = $component:expr) => {
102 log::debug!(component = $component; $fmt, $($args),+);
103 };
104
105 ($msg:literal, color = $color:expr) => {
107 log::debug!(color = $color as u8; $msg);
108 };
109 ($fmt:literal, $($args:expr),+, color = $color:expr) => {
110 log::debug!(color = $color as u8; $fmt, $($args),+);
111 };
112
113 ($msg:literal, color = $color:expr, component = $component:expr) => {
115 log::debug!(component = $component, color = $color as u8; $msg);
116 };
117 ($fmt:literal, $($args:expr),+, color = $color:expr, component = $component:expr) => {
118 log::debug!(component = $component, color = $color as u8; $fmt, $($args),+);
119 };
120
121 ($msg:literal, component = $component:expr, color = $color:expr) => {
123 log::debug!(component = $component, color = $color as u8; $msg);
124 };
125 ($fmt:literal, $($args:expr),+, component = $component:expr, color = $color:expr) => {
126 log::debug!(component = $component, color = $color as u8; $fmt, $($args),+);
127 };
128
129 ($msg:literal) => {
131 log::debug!(component = module_path!(), color = $crate::enums::LogColor::Normal as u8; $msg);
132 };
133 ($fmt:literal, $($args:expr),+) => {
134 log::debug!(component = module_path!(), color = $crate::enums::LogColor::Normal as u8; $fmt, $($args),+);
135 };
136}
137
138#[macro_export]
156macro_rules! log_info {
157 ($msg:literal, color = $color:expr, component = $component:expr) => {
159 log::info!(component = $component, color = $color as u8; $msg);
160 };
161 ($fmt:literal, $arg1:expr, color = $color:expr, component = $component:expr) => {
162 log::info!(component = $component, color = $color as u8; $fmt, $arg1);
163 };
164 ($fmt:literal, $arg1:expr, $arg2:expr, color = $color:expr, component = $component:expr) => {
165 log::info!(component = $component, color = $color as u8; $fmt, $arg1, $arg2);
166 };
167
168 ($msg:literal, component = $component:expr, color = $color:expr) => {
170 log::info!(component = $component, color = $color as u8; $msg);
171 };
172 ($fmt:literal, $arg1:expr, component = $component:expr, color = $color:expr) => {
173 log::info!(component = $component, color = $color as u8; $fmt, $arg1);
174 };
175 ($fmt:literal, $arg1:expr, $arg2:expr, component = $component:expr, color = $color:expr) => {
176 log::info!(component = $component, color = $color as u8; $fmt, $arg1, $arg2);
177 };
178
179 ($msg:literal, component = $component:expr) => {
181 log::info!(component = $component; $msg);
182 };
183 ($fmt:literal, $arg1:expr, component = $component:expr) => {
184 log::info!(component = $component; $fmt, $arg1);
185 };
186 ($fmt:literal, $arg1:expr, $arg2:expr, component = $component:expr) => {
187 log::info!(component = $component; $fmt, $arg1, $arg2);
188 };
189
190 ($msg:literal, color = $color:expr) => {
192 log::info!(color = $color as u8; $msg);
193 };
194 ($fmt:literal, $arg1:expr, color = $color:expr) => {
195 log::info!(color = $color as u8; $fmt, $arg1);
196 };
197 ($fmt:literal, $arg1:expr, $arg2:expr, color = $color:expr) => {
198 log::info!(color = $color as u8; $fmt, $arg1, $arg2);
199 };
200 ($fmt:literal, $arg1:expr, $arg2:expr, $arg3:expr, color = $color:expr) => {
201 log::info!(color = $color as u8; $fmt, $arg1, $arg2, $arg3);
202 };
203
204 ($msg:literal) => {
206 log::info!(component = module_path!(), color = $crate::enums::LogColor::Normal as u8; $msg);
207 };
208 ($fmt:literal, $($args:expr),+) => {
209 log::info!(component = module_path!(), color = $crate::enums::LogColor::Normal as u8; $fmt, $($args),+);
210 };
211}
212
213#[macro_export]
231macro_rules! log_warn {
232 ($msg:literal, color = $color:expr, component = $component:expr) => {
234 log::warn!(component = $component, color = $color as u8; $msg);
235 };
236 ($fmt:literal, $arg1:expr, color = $color:expr, component = $component:expr) => {
237 log::warn!(component = $component, color = $color as u8; $fmt, $arg1);
238 };
239 ($fmt:literal, $arg1:expr, $arg2:expr, color = $color:expr, component = $component:expr) => {
240 log::warn!(component = $component, color = $color as u8; $fmt, $arg1, $arg2);
241 };
242
243 ($msg:literal, component = $component:expr, color = $color:expr) => {
245 log::warn!(component = $component, color = $color as u8; $msg);
246 };
247 ($fmt:literal, $arg1:expr, component = $component:expr, color = $color:expr) => {
248 log::warn!(component = $component, color = $color as u8; $fmt, $arg1);
249 };
250 ($fmt:literal, $arg1:expr, $arg2:expr, component = $component:expr, color = $color:expr) => {
251 log::warn!(component = $component, color = $color as u8; $fmt, $arg1, $arg2);
252 };
253
254 ($msg:literal, component = $component:expr) => {
256 log::warn!(component = $component, color = $crate::enums::LogColor::Yellow as u8; $msg);
257 };
258 ($fmt:literal, $arg1:expr, component = $component:expr) => {
259 log::warn!(component = $component, color = $crate::enums::LogColor::Yellow as u8; $fmt, $arg1);
260 };
261 ($fmt:literal, $arg1:expr, $arg2:expr, component = $component:expr) => {
262 log::warn!(component = $component, color = $crate::enums::LogColor::Yellow as u8; $fmt, $arg1, $arg2);
263 };
264
265 ($msg:literal, color = $color:expr) => {
267 log::warn!(color = $color as u8; $msg);
268 };
269 ($fmt:literal, $arg1:expr, color = $color:expr) => {
270 log::warn!(color = $color as u8; $fmt, $arg1);
271 };
272 ($fmt:literal, $arg1:expr, $arg2:expr, color = $color:expr) => {
273 log::warn!(color = $color as u8; $fmt, $arg1, $arg2);
274 };
275 ($fmt:literal, $arg1:expr, $arg2:expr, $arg3:expr, color = $color:expr) => {
276 log::warn!(color = $color as u8; $fmt, $arg1, $arg2, $arg3);
277 };
278
279 ($msg:literal) => {
281 log::warn!(component = module_path!(), color = $crate::enums::LogColor::Yellow as u8; $msg);
282 };
283 ($fmt:literal, $($args:expr),+) => {
284 log::warn!(component = module_path!(), color = $crate::enums::LogColor::Yellow as u8; $fmt, $($args),+);
285 };
286}
287
288#[macro_export]
306macro_rules! log_error {
307 ($msg:literal, color = $color:expr, component = $component:expr) => {
309 log::error!(component = $component, color = $color as u8; $msg);
310 };
311 ($fmt:literal, $arg1:expr, color = $color:expr, component = $component:expr) => {
312 log::error!(component = $component, color = $color as u8; $fmt, $arg1);
313 };
314 ($fmt:literal, $arg1:expr, $arg2:expr, color = $color:expr, component = $component:expr) => {
315 log::error!(component = $component, color = $color as u8; $fmt, $arg1, $arg2);
316 };
317
318 ($msg:literal, component = $component:expr, color = $color:expr) => {
320 log::error!(component = $component, color = $color as u8; $msg);
321 };
322 ($fmt:literal, $arg1:expr, component = $component:expr, color = $color:expr) => {
323 log::error!(component = $component, color = $color as u8; $fmt, $arg1);
324 };
325 ($fmt:literal, $arg1:expr, $arg2:expr, component = $component:expr, color = $color:expr) => {
326 log::error!(component = $component, color = $color as u8; $fmt, $arg1, $arg2);
327 };
328
329 ($msg:literal, component = $component:expr) => {
331 log::error!(component = $component, color = $crate::enums::LogColor::Red as u8; $msg);
332 };
333 ($fmt:literal, $arg1:expr, component = $component:expr) => {
334 log::error!(component = $component, color = $crate::enums::LogColor::Red as u8; $fmt, $arg1);
335 };
336 ($fmt:literal, $arg1:expr, $arg2:expr, component = $component:expr) => {
337 log::error!(component = $component, color = $crate::enums::LogColor::Red as u8; $fmt, $arg1, $arg2);
338 };
339
340 ($msg:literal, color = $color:expr) => {
342 log::error!(color = $color as u8; $msg);
343 };
344 ($fmt:literal, $arg1:expr, color = $color:expr) => {
345 log::error!(color = $color as u8; $fmt, $arg1);
346 };
347 ($fmt:literal, $arg1:expr, $arg2:expr, color = $color:expr) => {
348 log::error!(color = $color as u8; $fmt, $arg1, $arg2);
349 };
350 ($fmt:literal, $arg1:expr, $arg2:expr, $arg3:expr, color = $color:expr) => {
351 log::error!(color = $color as u8; $fmt, $arg1, $arg2, $arg3);
352 };
353
354 ($msg:literal) => {
356 log::error!(component = module_path!(), color = $crate::enums::LogColor::Red as u8; $msg);
357 };
358 ($fmt:literal, $($args:expr),+) => {
359 log::error!(component = module_path!(), color = $crate::enums::LogColor::Red as u8; $fmt, $($args),+);
360 };
361}
362
363pub use log_debug;
365pub use log_error;
366pub use log_info;
367pub use log_trace;
368pub use log_warn;
369
370#[cfg(all(test, not(all(feature = "simulation", madsim))))]
375mod tests {
376 use std::{thread::sleep, time::Duration};
377
378 use nautilus_core::UUID4;
379 use nautilus_model::identifiers::TraderId;
380 use rstest::*;
381 use tempfile::tempdir;
382
383 use crate::{
384 enums::LogColor,
385 logging::{
386 logger::{Logger, LoggerConfig},
387 logging_clock_set_static_mode, logging_clock_set_static_time,
388 writer::FileWriterConfig,
389 },
390 testing::wait_until,
391 };
392
393 #[rstest]
394 fn test_colored_logging_macros() {
395 let config = LoggerConfig::from_spec("stdout=Trace;fileout=Trace;is_colored").unwrap();
396
397 let temp_dir = tempdir().expect("Failed to create temporary directory");
398 let file_config = FileWriterConfig {
399 directory: Some(temp_dir.path().to_str().unwrap().to_string()),
400 ..Default::default()
401 };
402
403 let log_guard = Logger::init_with_config(
404 TraderId::from("TRADER-001"),
405 UUID4::new(),
406 config,
407 file_config,
408 )
409 .expect("Failed to initialize logger");
410
411 logging_clock_set_static_mode();
412 logging_clock_set_static_time(1_650_000_000_000_000);
413
414 log_trace!("This is a trace message", component = "TestComponent");
416 log_debug!("This is a debug message", component = "TestComponent");
417 log_info!("This is an info message", component = "TestComponent");
418 log_warn!("This is a warning message", component = "TestComponent");
419 log_error!("This is an error message", component = "TestComponent");
420
421 log_info!(
423 "Success message",
424 color = LogColor::Green,
425 component = "TestComponent"
426 );
427 log_info!(
428 "Information message",
429 color = LogColor::Blue,
430 component = "TestComponent"
431 );
432 log_warn!(
433 "Custom warning",
434 component = "TestComponent",
435 color = LogColor::Magenta
436 );
437
438 log_info!("Component test", component = "TestComponent");
440 log_warn!("Component warning", component = "TestComponent");
441
442 log_info!(
444 "Color then component",
445 color = LogColor::Cyan,
446 component = "TestComponent"
447 );
448
449 sleep(Duration::from_millis(200));
451
452 drop(log_guard);
453
454 let mut log_contents = String::new();
456 wait_until(
457 || {
458 if let Some(log_file) = std::fs::read_dir(&temp_dir)
459 .expect("Failed to read directory")
460 .filter_map(Result::ok)
461 .find(|entry| entry.path().is_file())
462 {
463 let log_file_path = log_file.path();
464 log_contents =
465 std::fs::read_to_string(log_file_path).expect("Failed to read log file");
466 !log_contents.is_empty()
467 } else {
468 false
469 }
470 },
471 Duration::from_secs(3),
472 );
473
474 if !log_contents.contains("This is a trace message") {
476 println!("File contents:\n{log_contents}");
477 }
478
479 assert!(log_contents.contains("This is a trace message"));
481 assert!(log_contents.contains("This is a debug message"));
482 assert!(log_contents.contains("This is an info message"));
483 assert!(log_contents.contains("This is a warning message"));
484 assert!(log_contents.contains("This is an error message"));
485 assert!(log_contents.contains("Success message"));
486 assert!(log_contents.contains("Information message"));
487 assert!(log_contents.contains("Custom warning"));
488
489 assert!(log_contents.contains("Component test"));
491 assert!(log_contents.contains("Component warning"));
492 assert!(log_contents.contains("Color then component"));
493 }
494
495 #[rstest]
496 fn test_default_macro_captures_module_path() {
497 let config = LoggerConfig::from_spec(
504 "stdout=Off;fileout=Trace;nautilus_common::logging::macros=Debug",
505 )
506 .unwrap();
507
508 let temp_dir = tempdir().expect("Failed to create temporary directory");
509 let file_config = FileWriterConfig {
510 directory: Some(temp_dir.path().to_str().unwrap().to_string()),
511 ..Default::default()
512 };
513
514 let log_guard = Logger::init_with_config(
515 TraderId::from("TRADER-PATH"),
516 UUID4::new(),
517 config,
518 file_config,
519 )
520 .expect("Failed to initialize logger");
521
522 logging_clock_set_static_mode();
523 logging_clock_set_static_time(1_650_000_000_000_000);
524
525 log_info!("Auto-captured module path message");
527 log_debug!("Debug level auto-captured");
528
529 log_trace!("Trace should be filtered SHOULD_NOT_APPEAR");
531
532 sleep(Duration::from_millis(200));
533 drop(log_guard);
534
535 let mut log_contents = String::new();
536 wait_until(
537 || {
538 if let Some(log_file) = std::fs::read_dir(&temp_dir)
539 .expect("Failed to read directory")
540 .filter_map(Result::ok)
541 .find(|entry| entry.path().is_file())
542 {
543 log_contents =
544 std::fs::read_to_string(log_file.path()).expect("Failed to read log file");
545 !log_contents.is_empty()
546 } else {
547 false
548 }
549 },
550 Duration::from_secs(3),
551 );
552
553 assert!(
554 log_contents.contains("nautilus_common::logging::macros"),
555 "Component should contain module path, was:\n{log_contents}"
556 );
557 assert!(
558 log_contents.contains("Auto-captured module path message"),
559 "Info message should pass"
560 );
561 assert!(
562 log_contents.contains("Debug level auto-captured"),
563 "Debug message should pass"
564 );
565 assert!(
566 !log_contents.contains("SHOULD_NOT_APPEAR"),
567 "Trace should be filtered by module filter"
568 );
569 }
570}