kasl/libs/messages/macros.rs
1//! Convenient macros for application messaging and logging.
2//!
3//! Provides a comprehensive set of macros that simplify message display and logging throughout the application with automatic debug mode detection.
4//!
5//! ## Features
6//!
7//! - **Dual Output Mode**: Automatic switching between tracing and console output
8//! - **Debug Detection**: Runtime detection of debug mode configuration
9//! - **Message Categorization**: Different macros for different message types
10//! - **Performance Optimization**: Cached debug mode detection for efficiency
11//! - **Error Handling**: Specialized macros for error creation and handling
12//!
13//! ## Usage
14//!
15//! ```rust
16//! use kasl::{msg_info, msg_error, msg_success, msg_warning};
17//! use kasl::libs::messages::types::Message;
18//!
19//! // Basic message display
20//! msg_info!(Message::TaskCreated);
21//! msg_success!(Message::ReportSent("2025-01-15".to_string()));
22//! msg_error!(Message::ConfigSaveError);
23//!
24//! // Custom formatted messages
25//! msg_info!(format!("Processing {} items", count));
26//! ```
27
28/// Convenience macros for common message operations with conditional tracing support
29use std::sync::OnceLock;
30
31/// Global cache for debug mode detection to avoid repeated environment variable checks.
32///
33/// This static variable uses `OnceLock` to cache the result of debug mode detection
34/// on first access. This provides significant performance benefits by avoiding
35/// repeated environment variable lookups, which can be expensive operations.
36///
37/// ## Performance Benefits
38/// - **Single Check**: Environment variables are checked only once per application run
39/// - **Fast Access**: Subsequent checks are simple memory reads
40/// - **Thread Safety**: OnceLock provides thread-safe initialization
41/// - **Memory Efficiency**: Minimal memory overhead for caching
42static DEBUG_MODE: OnceLock<bool> = OnceLock::new();
43
44/// Checks if debug mode is enabled, with caching for performance.
45///
46/// This function determines whether the application is running in debug mode
47/// by checking for the presence of debug-related environment variables. The
48/// result is cached using `OnceLock` to avoid repeated expensive environment
49/// variable lookups.
50///
51/// ## Detection Logic
52///
53/// Debug mode is considered enabled if either of these environment variables is set:
54/// - **`KASL_DEBUG`**: Application-specific debug flag
55/// - **`RUST_LOG`**: Standard Rust logging configuration
56///
57/// The presence of either variable indicates that the user wants enhanced
58/// logging output and expects debug information to be available.
59///
60/// ## Caching Strategy
61///
62/// The function uses a lazy initialization pattern:
63/// 1. **First Call**: Checks environment variables and caches result
64/// 2. **Subsequent Calls**: Returns cached value without environment checks
65/// 3. **Thread Safety**: Multiple threads can safely call this function
66/// 4. **Performance**: Subsequent calls are essentially free
67///
68/// ## Integration Points
69///
70/// This function is used by all message macros to determine output routing:
71/// - **Debug Mode**: Messages go to tracing system with structured logging
72/// - **Normal Mode**: Messages go to simple console output (println!/eprintln!)
73///
74/// # Returns
75///
76/// Returns `true` if debug mode is enabled, `false` otherwise. The result
77/// is cached for the lifetime of the application.
78///
79/// # Examples
80///
81/// ```rust
82/// use kasl::libs::messages::macros::is_debug_mode;
83///
84/// if is_debug_mode() {
85/// println!("Running in debug mode with enhanced logging");
86/// } else {
87/// println!("Running in normal mode with simple output");
88/// }
89/// ```
90#[doc(hidden)]
91pub fn is_debug_mode() -> bool {
92 *DEBUG_MODE.get_or_init(|| {
93 // Check for application-specific debug flag
94 std::env::var("KASL_DEBUG").is_ok() ||
95 // Check for standard Rust logging configuration
96 std::env::var("RUST_LOG").is_ok()
97 })
98}
99
100/// Prints a general message with automatic debug mode routing.
101///
102/// This macro provides the basic message display functionality with automatic
103/// detection of debug mode to route output appropriately. It supports both
104/// simple single-line messages and formatted messages with optional line breaks.
105///
106/// ## Output Routing
107///
108/// - **Debug Mode**: Uses `tracing::info!` for structured logging
109/// - **Normal Mode**: Uses `println!` for simple console output
110///
111/// ## Usage Patterns
112///
113/// ### Simple Message
114/// ```rust
115/// msg_print!(Message::ConfigSaved);
116/// // Output: "Configuration saved successfully"
117/// ```
118///
119/// ### Message with Line Breaks
120/// ```rust
121/// msg_print!(Message::ReportHeader, true);
122/// // Output: "\nš Daily Work Report\n"
123/// ```
124///
125/// ## Performance Notes
126///
127/// - Debug mode detection is cached for efficiency
128/// - Tracing integration provides structured logging in debug mode
129/// - Simple println! provides fast output in production mode
130#[macro_export]
131macro_rules! msg_print {
132 ($msg:expr) => {
133 if $crate::libs::messages::macros::is_debug_mode() {
134 tracing::info!("{}", $msg);
135 } else {
136 println!("{}", $msg);
137 }
138 };
139 ($msg:expr, true) => {
140 if $crate::libs::messages::macros::is_debug_mode() {
141 tracing::info!("\n{}\n", $msg);
142 } else {
143 println!("\n{}\n", $msg);
144 }
145 };
146}
147
148/// Prints a success message with ā
prefix and automatic routing.
149///
150/// This macro is specifically designed for displaying success notifications
151/// and positive confirmations. The green checkmark emoji provides visual
152/// confirmation that operations completed successfully.
153///
154/// ## Visual Design
155///
156/// - **Prefix**: ā
(green checkmark emoji)
157/// - **Purpose**: Success confirmations and positive outcomes
158/// - **Examples**: Task creation, configuration saves, successful exports
159///
160/// ## Output Examples
161///
162/// ```text
163/// ā
Task created successfully
164/// ā
Configuration saved successfully
165/// ā
Data exported to file.csv
166/// ```
167///
168/// ## Usage Patterns
169///
170/// ### Simple Success Message
171/// ```rust
172/// msg_success!(Message::TaskCreated);
173/// // Output: "ā
Task created successfully"
174/// ```
175///
176/// ### Success Message with Line Breaks
177/// ```rust
178/// msg_success!(Message::ExportSuccess("data.csv".to_string()), true);
179/// // Output: "\nā
Data exported successfully to: data.csv\n"
180/// ```
181#[macro_export]
182macro_rules! msg_success {
183 ($msg:expr) => {
184 if $crate::libs::messages::macros::is_debug_mode() {
185 tracing::info!("ā
{}", $msg);
186 } else {
187 println!("ā
{}", $msg);
188 }
189 };
190 ($msg:expr, true) => {
191 if $crate::libs::messages::macros::is_debug_mode() {
192 tracing::info!("\nā
{}\n", $msg);
193 } else {
194 println!("\nā
{}\n", $msg);
195 }
196 };
197}
198
199/// Prints an error message with ā prefix and automatic routing.
200///
201/// This macro handles error message display with appropriate severity level
202/// routing. In debug mode, errors are logged through the tracing system,
203/// while in normal mode they're displayed on stderr for proper error handling.
204///
205/// ## Visual Design
206///
207/// - **Prefix**: ā (red X emoji)
208/// - **Purpose**: Error notifications and failure messages
209/// - **Stream**: Uses stderr in normal mode for proper error stream handling
210///
211/// ## Output Routing
212///
213/// - **Debug Mode**: Uses `tracing::error!` for structured error logging
214/// - **Normal Mode**: Uses `eprintln!` to write to stderr
215///
216/// ## Error Stream Benefits
217///
218/// Using stderr for error output provides several advantages:
219/// - **Stream Separation**: Errors don't interfere with normal output
220/// - **Script Compatibility**: Scripts can separate errors from data
221/// - **Shell Redirection**: Users can redirect errors independently
222/// - **Log Aggregation**: Error logs can be collected separately
223///
224/// ## Usage Patterns
225///
226/// ### Simple Error Message
227/// ```rust
228/// msg_error!(Message::TaskNotFound);
229/// // Output to stderr: "ā Task not found"
230/// ```
231///
232/// ### Error Message with Line Breaks
233/// ```rust
234/// msg_error!(Message::ConfigParseError, true);
235/// // Output to stderr: "\nā Failed to parse configuration file\n"
236/// ```
237#[macro_export]
238macro_rules! msg_error {
239 ($msg:expr) => {
240 if $crate::libs::messages::macros::is_debug_mode() {
241 tracing::error!("ā {}", $msg);
242 } else {
243 eprintln!("ā {}", $msg);
244 }
245 };
246 ($msg:expr, true) => {
247 if $crate::libs::messages::macros::is_debug_mode() {
248 tracing::error!("\nā {}\n", $msg);
249 } else {
250 eprintln!("\nā {}\n", $msg);
251 }
252 };
253}
254
255/// Prints a warning message with ā ļø prefix and automatic routing.
256///
257/// This macro displays warning messages that indicate potential issues or
258/// situations requiring user attention, but which don't prevent operation
259/// from continuing. Warnings help users understand system state and make
260/// informed decisions.
261///
262/// ## Visual Design
263///
264/// - **Prefix**: ā ļø (warning triangle emoji)
265/// - **Purpose**: Cautionary messages and non-critical issues
266/// - **Severity**: Less critical than errors, more important than info
267///
268/// ## Warning Categories
269///
270/// Warnings are appropriate for:
271/// - **Deprecated Features**: Features that will be removed in future versions
272/// - **Configuration Issues**: Non-critical configuration problems
273/// - **Performance Concerns**: Operations that may be slow or inefficient
274/// - **Fallback Behavior**: When the system falls back to default behavior
275/// - **Resource Limitations**: When approaching resource limits
276///
277/// ## Usage Patterns
278///
279/// ### Simple Warning Message
280/// ```rust
281/// msg_warning!(Message::AutostartCheckingAlternative);
282/// // Output: "ā ļø Checking alternative autostart methods..."
283/// ```
284///
285/// ### Warning Message with Line Breaks
286/// ```rust
287/// msg_warning!(Message::SignalHandlingNotSupported, true);
288/// // Output: "\nā ļø Signal handling not supported on this platform\n"
289/// ```
290#[macro_export]
291macro_rules! msg_warning {
292 ($msg:expr) => {
293 if $crate::libs::messages::macros::is_debug_mode() {
294 tracing::warn!("ā ļø {}", $msg);
295 } else {
296 println!("ā ļø {}", $msg);
297 }
298 };
299 ($msg:expr, true) => {
300 if $crate::libs::messages::macros::is_debug_mode() {
301 tracing::warn!("\nā ļø {}\n", $msg);
302 } else {
303 println!("\nā ļø {}\n", $msg);
304 }
305 };
306}
307
308/// Prints an informational message with ā¹ļø prefix and automatic routing.
309///
310/// This macro displays informational messages that provide useful context
311/// or status updates to users. Info messages help users understand what
312/// the system is doing and provide transparency into system operations.
313///
314/// ## Visual Design
315///
316/// - **Prefix**: ā¹ļø (information emoji)
317/// - **Purpose**: Status updates and informational content
318/// - **Tone**: Neutral, informative, helpful
319///
320/// ## Information Categories
321///
322/// Info messages are appropriate for:
323/// - **Status Updates**: Progress information for long-running operations
324/// - **System State**: Current system status and configuration
325/// - **Process Information**: What the system is currently doing
326/// - **User Guidance**: Helpful tips and usage information
327/// - **Confirmation**: Non-critical confirmations and acknowledgments
328///
329/// ## Usage Patterns
330///
331/// ### Simple Info Message
332/// ```rust
333/// msg_info!(Message::WatcherStarted(1234));
334/// // Output: "ā¹ļø Watcher started with PID: 1234"
335/// ```
336///
337/// ### Info Message with Line Breaks
338/// ```rust
339/// msg_info!(Message::MonthlySummaryHeader, true);
340/// // Output: "\nā¹ļø š
Monthly Summary\n"
341/// ```
342#[macro_export]
343macro_rules! msg_info {
344 ($msg:expr) => {
345 if $crate::libs::messages::macros::is_debug_mode() {
346 tracing::info!("ā¹ļø {}", $msg);
347 } else {
348 println!("ā¹ļø {}", $msg);
349 }
350 };
351 ($msg:expr, true) => {
352 if $crate::libs::messages::macros::is_debug_mode() {
353 tracing::info!("\nā¹ļø {}\n", $msg);
354 } else {
355 println!("\nā¹ļø {}\n", $msg);
356 }
357 };
358}
359
360/// Debug-only message display with š prefix.
361///
362/// This macro provides debug-specific logging that only appears when debug
363/// mode is explicitly enabled. Debug messages are useful for troubleshooting
364/// and development but are hidden from normal users to avoid clutter.
365///
366/// ## Debug-Only Behavior
367///
368/// - **Debug Mode**: Messages are displayed using `tracing::debug!`
369/// - **Normal Mode**: Messages are completely suppressed (no output)
370/// - **Performance**: No overhead in production builds when debug is disabled
371///
372/// ## Visual Design
373///
374/// - **Prefix**: š (magnifying glass emoji)
375/// - **Purpose**: Development and troubleshooting information
376/// - **Audience**: Developers and power users debugging issues
377///
378/// ## Debug Message Categories
379///
380/// Debug messages are appropriate for:
381/// - **Technical Details**: Low-level system information
382/// - **State Changes**: Internal state transitions and updates
383/// - **Performance Metrics**: Timing and performance measurements
384/// - **Data Flow**: How data moves through the system
385/// - **Error Context**: Additional context for debugging errors
386///
387/// ## Usage Patterns
388///
389/// ### Technical Debug Information
390/// ```rust
391/// msg_debug!("Processing task with ID: {}", task_id);
392/// // Debug mode output: "š Processing task with ID: 42"
393/// // Normal mode output: (nothing)
394/// ```
395///
396/// ### State Change Debugging
397/// ```rust
398/// msg_debug!(format!("State transition: {:?} -> {:?}", old_state, new_state));
399/// // Debug mode output: "š State transition: Active -> InPause"
400/// // Normal mode output: (nothing)
401/// ```
402#[macro_export]
403macro_rules! msg_debug {
404 ($msg:expr) => {
405 if $crate::libs::messages::macros::is_debug_mode() {
406 tracing::debug!("š {}", $msg);
407 }
408 };
409}
410
411/// Creates an `anyhow::Error` from a message with ā prefix.
412///
413/// This macro provides a convenient way to create `anyhow::Error` instances
414/// from application messages. It's useful for error propagation in functions
415/// that return `Result<T, anyhow::Error>` and need to convert application
416/// messages into proper error types.
417///
418/// ## Error Creation Strategy
419///
420/// - **Prefix Addition**: Automatically adds ā prefix for visual consistency
421/// - **Error Propagation**: Creates errors suitable for `?` operator use
422/// - **Message Integration**: Works with the application's message system
423/// - **Type Compatibility**: Returns `anyhow::Error` for easy integration
424///
425/// ## Use Cases
426///
427/// ### Function Error Returns
428/// ```rust
429/// use anyhow::Result;
430/// use kasl::{msg_error_anyhow, libs::messages::Message};
431///
432/// fn validate_config() -> Result<()> {
433/// if config_is_invalid() {
434/// return Err(msg_error_anyhow!(Message::ConfigParseError));
435/// }
436/// Ok(())
437/// }
438/// ```
439///
440/// ### Error Context Addition
441/// ```rust
442/// use anyhow::{Result, Context};
443///
444/// fn complex_operation() -> Result<()> {
445/// some_operation()
446/// .context(msg_error_anyhow!(Message::OperationFailed))
447/// }
448/// ```
449///
450/// ## Error Handling Benefits
451///
452/// - **Consistent Formatting**: All errors have consistent visual presentation
453/// - **Message Reuse**: Leverages existing message definitions
454/// - **Type Safety**: Provides proper error types for Rust's error handling
455/// - **Integration**: Works seamlessly with `anyhow` and `?` operator
456#[macro_export]
457macro_rules! msg_error_anyhow {
458 ($msg:expr) => {
459 anyhow::anyhow!("ā {}", $msg)
460 };
461}
462
463/// Early return with an error created from a message.
464///
465/// This macro combines error creation with immediate return, providing a
466/// convenient way to exit functions early when error conditions are detected.
467/// It's equivalent to `return Err(msg_error_anyhow!(message))` but more concise.
468///
469/// ## Early Return Pattern
470///
471/// - **Error Creation**: Creates an `anyhow::Error` with ā prefix
472/// - **Immediate Return**: Returns the error immediately from the function
473/// - **Function Exit**: Stops execution at the point of the macro call
474/// - **Clean Code**: Reduces boilerplate for error handling
475///
476/// ## Use Cases
477///
478/// ### Input Validation
479/// ```rust
480/// use anyhow::Result;
481/// use kasl::{msg_bail_anyhow, libs::messages::Message};
482///
483/// fn process_task(task_id: Option<i32>) -> Result<()> {
484/// let id = task_id.unwrap_or_else(|| {
485/// msg_bail_anyhow!(Message::InvalidInput);
486/// });
487///
488/// // Continue processing with valid ID
489/// Ok(())
490/// }
491/// ```
492///
493/// ### Permission Checking
494/// ```rust
495/// fn secure_operation() -> Result<()> {
496/// if !user_has_permission() {
497/// msg_bail_anyhow!(Message::PermissionDenied);
498/// }
499///
500/// // Continue with authorized operation
501/// Ok(())
502/// }
503/// ```
504///
505/// ### Resource Validation
506/// ```rust
507/// fn access_resource(path: &str) -> Result<()> {
508/// if !resource_exists(path) {
509/// msg_bail_anyhow!(Message::ResourceNotFound);
510/// }
511///
512/// // Continue with valid resource
513/// Ok(())
514/// }
515/// ```
516///
517/// ## Code Style Benefits
518///
519/// - **Reduced Boilerplate**: Eliminates repetitive error handling code
520/// - **Clear Intent**: Makes error conditions immediately obvious
521/// - **Consistent Errors**: All bail errors have consistent formatting
522/// - **Maintainability**: Easier to update error handling patterns
523#[macro_export]
524macro_rules! msg_bail_anyhow {
525 ($msg:expr) => {
526 anyhow::bail!("ā {}", $msg)
527 };
528}