1use std::fmt;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
7pub enum LogLevel {
8 Trace = 0,
10 Debug = 1,
12 Info = 2,
14 Warn = 3,
16 Error = 4,
18}
19
20impl fmt::Display for LogLevel {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 match self {
23 Self::Trace => write!(f, "TRACE"),
24 Self::Debug => write!(f, "DEBUG"),
25 Self::Info => write!(f, "INFO"),
26 Self::Warn => write!(f, "WARN"),
27 Self::Error => write!(f, "ERROR"),
28 }
29 }
30}
31
32#[derive(Debug)]
41pub struct Logger {
42 level: LogLevel,
43 module: String,
44}
45
46impl Logger {
47 #[must_use]
49 pub fn new(module: &str) -> Self {
50 Self {
51 level: LogLevel::Info,
52 module: module.to_string(),
53 }
54 }
55
56 pub const fn set_level(&mut self, level: LogLevel) {
58 self.level = level;
59 }
60
61 pub fn log(&self, level: LogLevel, message: &str) {
63 if level >= self.level {
64 let timestamp = Self::timestamp();
65 println!("[{timestamp}] {level} [{}] {message}", self.module);
66 }
67 }
68
69 #[cfg(feature = "time")]
76 fn timestamp() -> u64 {
77 crate::time::unix_timestamp()
78 }
79
80 #[cfg(not(feature = "time"))]
82 fn timestamp() -> u64 {
83 use std::time::{SystemTime, UNIX_EPOCH};
84 SystemTime::now()
85 .duration_since(UNIX_EPOCH)
86 .unwrap_or_default()
87 .as_secs()
88 }
89
90 pub fn trace(&self, message: &str) {
92 self.log(LogLevel::Trace, message);
93 }
94
95 pub fn debug(&self, message: &str) {
97 self.log(LogLevel::Debug, message);
98 }
99
100 pub fn info(&self, message: &str) {
102 self.log(LogLevel::Info, message);
103 }
104
105 pub fn warn(&self, message: &str) {
107 self.log(LogLevel::Warn, message);
108 }
109
110 pub fn error(&self, message: &str) {
112 self.log(LogLevel::Error, message);
113 }
114}
115
116#[cfg(feature = "logging")]
122#[macro_export]
123macro_rules! logger {
124 () => {
125 $crate::logging::Logger::new(module_path!())
126 };
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 #[test]
134 fn test_logger_basic() {
135 let logger = Logger::new("test_module");
136 logger.info("basic log test");
139 }
140
141 #[test]
142 fn test_logger_level_filtering() {
143 let mut logger = Logger::new("filter_test");
144 logger.set_level(LogLevel::Warn);
145
146 logger.trace("should be filtered");
148 logger.debug("should be filtered");
149 logger.info("should be filtered");
150
151 logger.warn("visible warning");
153 logger.error("visible error");
154 }
155}