daemon_console/
logger.rs

1//! Logging utilities with colored terminal output.
2//!
3//! This module provides a logging system with different severity levels
4//! (Info, Warn, Error, Debug) and automatic timestamp formatting.
5
6use chrono::Local;
7use crossterm::style::{self, Color, ResetColor, SetForegroundColor};
8
9/// Log level enumeration for categorizing log messages.
10#[derive(Debug, PartialEq, Eq, Copy, Clone)]
11pub enum LogLevel {
12    Info,
13    Warn,
14    Error,
15    Debug,
16    Critical,
17}
18
19/// Formats a log message with timestamp, level indicator, and color coding.
20///
21/// # Arguments
22///
23/// * `level` - Severity level of the log message
24/// * `message` - Content of the log message
25/// * `module_name` - Optional module name prefix
26///
27/// # Returns
28///
29/// Formatted string with ANSI color codes for terminal display
30///
31/// # Examples
32///
33/// ```
34/// use daemon_console::logger::{log_message, LogLevel};
35///
36/// let msg = log_message(LogLevel::Info, "Application started", Some("main"));
37/// println!("{}", msg);
38/// ```
39pub fn log_message(level: LogLevel, message: &str, module_name: Option<&str>) -> String {
40    let now = Local::now();
41    let timestamp = now.format("%H:%M:%S").to_string();
42
43    let (level_str, color) = match level {
44        LogLevel::Info => ("INFO", Color::Green),
45        LogLevel::Warn => ("WARN", Color::Yellow),
46        LogLevel::Error => ("ERROR", Color::Red),
47        LogLevel::Debug => ("DEBUG", Color::DarkGrey),
48        LogLevel::Critical => ("CRITICAL", Color::AnsiValue(5)),
49    };
50
51    let module_prefix = module_name.map_or_else(String::new, |name| format!("{}/", name));
52
53    match level {
54        LogLevel::Info | LogLevel::Warn | LogLevel::Error | LogLevel::Critical => {
55            format!(
56                "[{}] {}[{}{}{}{}{}]{} {}{}",
57                timestamp,
58                style::Attribute::Bold,
59                module_prefix,
60                SetForegroundColor(color),
61                level_str,
62                ResetColor,
63                style::Attribute::Bold,
64                ResetColor,
65                message,
66                ResetColor
67            )
68        }
69        LogLevel::Debug => {
70            format!(
71                "{}{}[{}] [{}{}] {}{}{}",
72                SetForegroundColor(color),
73                style::Attribute::Italic,
74                timestamp,
75                module_prefix,
76                level_str,
77                style::Attribute::Italic,
78                message,
79                ResetColor,
80            )
81        }
82    }
83}
84
85/// Format multi-line messages with log-levels.
86///
87/// > Middleware method for macros like `get_info!`.
88pub fn format_multiline_message(
89    level: LogLevel,
90    message: &str,
91    module_name: Option<&str>,
92) -> String {
93    if !message.contains('\n') {
94        return log_message(level, message, module_name);
95    }
96
97    message
98        .lines()
99        .map(|line| log_message(level, line, module_name))
100        .collect::<Vec<String>>()
101        .join("\n")
102}
103
104/// Macro for creating info-level log messages.
105///
106/// # Examples
107///
108/// ```
109/// use daemon_console::get_info;
110///
111/// let msg = get_info!("Server started");
112/// let msg_with_module = get_info!("Database connected", "db");
113/// ```
114#[macro_export]
115macro_rules! get_info {
116    ($message:expr) => {
117        $crate::logger::format_multiline_message($crate::logger::LogLevel::Info, $message, None)
118    };
119    ($message:expr, $module_name:expr) => {
120        $crate::logger::format_multiline_message(
121            $crate::logger::LogLevel::Info,
122            $message,
123            Some($module_name),
124        )
125    };
126}
127
128/// Macro for creating warning-level log messages.
129///
130/// # Examples
131///
132/// ```
133/// use daemon_console::get_warn;
134///
135/// let msg = get_warn!("Memory usage high");
136/// let msg_with_module = get_warn!("Connection timeout", "network");
137/// ```
138#[macro_export]
139macro_rules! get_warn {
140    ($message:expr) => {
141        $crate::logger::format_multiline_message($crate::logger::LogLevel::Warn, $message, None)
142    };
143    ($message:expr, $module_name:expr) => {
144        $crate::logger::format_multiline_message(
145            $crate::logger::LogLevel::Warn,
146            $message,
147            Some($module_name),
148        )
149    };
150}
151
152/// Macro for creating error-level log messages.
153///
154/// # Examples
155///
156/// ```
157/// use daemon_console::get_error;
158///
159/// let msg = get_error!("Failed to connect");
160/// let msg_with_module = get_error!("Authentication failed", "auth");
161/// ```
162#[macro_export]
163macro_rules! get_error {
164    ($message:expr) => {
165        $crate::logger::format_multiline_message($crate::logger::LogLevel::Error, $message, None)
166    };
167    ($message:expr, $module_name:expr) => {
168        $crate::logger::format_multiline_message(
169            $crate::logger::LogLevel::Error,
170            $message,
171            Some($module_name),
172        )
173    };
174}
175
176/// Macro for creating debug-level log messages.
177///
178/// # Examples
179///
180/// ```
181/// use daemon_console::get_debug;
182///
183/// let msg = get_debug!("Variable value: 42");
184/// let msg_with_module = get_debug!("Request received", "http");
185/// ```
186#[macro_export]
187macro_rules! get_debug {
188    ($message:expr) => {
189        $crate::logger::format_multiline_message($crate::logger::LogLevel::Debug, $message, None)
190    };
191    ($message:expr, $module_name:expr) => {
192        $crate::logger::format_multiline_message(
193            $crate::logger::LogLevel::Debug,
194            $message,
195            Some($module_name),
196        )
197    };
198}
199
200/// Macro for creating critical-level log messages.
201///
202/// # Examples
203///
204/// ```
205/// use daemon_console::get_critical;
206///
207/// let msg = get_critical!("Critical error");
208/// let msg_with_module = get_critical!("Critical error", "database");
209/// ```
210#[macro_export]
211macro_rules! get_critical {
212    ($message:expr) => {
213        $crate::logger::format_multiline_message($crate::logger::LogLevel::Critical, $message, None)
214    };
215    ($message:expr, $module_name:expr) => {
216        $crate::logger::format_multiline_message(
217            $crate::logger::LogLevel::Critical,
218            $message,
219            Some($module_name),
220        )
221    };
222}