Skip to main content

osal_rs/
log.rs

1/***************************************************************************
2 *
3 * osal-rs
4 * Copyright (C) 2026 Antonio Salsi <passy.linux@zresa.it>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <https://www.gnu.org/licenses/>.
18 *
19 ***************************************************************************/
20
21//! Logging system for embedded environments.
22//!
23//! Provides a flexible logging system with multiple severity levels and color support.
24//! Designed for no-std environments with UART output support.
25//!
26//! # Features
27//!
28//! - Multiple log levels (DEBUG, INFO, WARNING, ERROR, FATAL)
29//! - Color-coded output support (ANSI colors)
30//! - Timestamp logging with millisecond precision
31//! - Thread-safe logging with busy-wait synchronization
32//! - Configurable log level masking
33//! - Zero-cost when logs are disabled
34//!
35//! # Examples
36//!
37//! ## Basic logging
38//!
39//! ```ignore
40//! use osal_rs::{log_info, log_error, log_debug};
41//! 
42//! log_info!("APP", "Application started");
43//! log_debug!("APP", "Counter value: {}", 42);
44//! log_error!("APP", "Failed to initialize: {}", error_msg);
45//! ```
46//!
47//! ## Configuring log levels
48//!
49//! ```ignore
50//! use osal_rs::log::*;
51//! 
52//! // Set log level to WARNING and above
53//! set_level_log(log_levels::LEVEL_WARNING);
54//! 
55//! // Enable/disable logging
56//! set_enable_log(true);
57//! 
58//! // Enable/disable color output
59//! set_enable_color(true);
60//! ```
61//!
62//! ## Using print macros
63//!
64//! ```ignore
65//! use osal_rs::{print, println};
66//! 
67//! print!("Hello");
68//! println!(" World!");
69//! println!("Value: {}", 123);
70//! ```
71//!
72//! # Thread Safety
73//!
74//! The logging system uses a simple busy-wait lock to ensure thread-safe output:
75//! - Only one thread can log at a time
76//! - Other threads spin-wait until the log is complete
77//! - No heap allocation during the lock
78//! - Suitable for task context only (see ISR Context below)
79//!
80//! # ISR Context
81//!
82//! **WARNING**: Do not use logging macros from interrupt service routines (ISRs).
83//! 
84//! Reasons:
85//! - Busy-wait lock can cause priority inversion
86//! - String formatting allocates memory
87//! - UART operations may block
88//! - Can significantly delay interrupt response
89//!
90//! If you need logging from ISR context, use a queue to defer the log to a task.
91//!
92//! # Performance Considerations
93//!
94//! - Each log call allocates a string (uses RTOS heap)
95//! - UART transmission is synchronous and relatively slow
96//! - Verbose logging (DEBUG level) can impact real-time performance
97//! - Consider using WARNING or ERROR level in production
98//! - Logs are compiled out when the level is disabled (zero cost)
99//!
100//! # Color Output
101//!
102//! When colors are enabled, log levels are color-coded:
103//! - **DEBUG**: Cyan - Detailed debugging information
104//! - **INFO**: Green - Normal operational messages
105//! - **WARNING**: Yellow - Potential issues, non-critical
106//! - **ERROR**: Red - Errors affecting functionality
107//! - **FATAL**: Magenta - Critical errors, system failure
108//!
109//! Disable colors if your terminal doesn't support ANSI escape codes.
110//!
111//! # Best Practices
112//!
113//! 1. **Use appropriate tags**: Use meaningful tags like "NET", "FS", "APP" to identify sources
114//! 2. **Choose correct levels**: DEBUG for development, INFO for milestones, ERROR for failures
115//! 3. **Avoid logging in hot paths**: Logging can significantly slow down tight loops
116//! 4. **Set production levels**: Use WARNING or ERROR level in production builds
117//! 5. **Never log from ISRs**: Defer to task context using queues or notifications
118
119#[cfg(not(feature = "std"))]
120pub mod ffi {
121    //! Foreign Function Interface (FFI) to C UART functions.
122    //!
123    //! This module provides low-level bindings to C functions for UART communication.
124    //! These functions are only available in `no_std` mode.
125    //!
126    //! # Safety
127    //!
128    //! All functions in this module are `unsafe` because they:
129    //! - Call external C code that cannot be verified by Rust
130    //! - Require valid C string pointers (null-terminated)
131    //! - May access hardware registers directly
132    //! - Do not perform bounds checking
133    //!
134    //! # Platform Requirements
135    //!
136    //! The C implementation must provide `printf_on_uart` that:
137    //! - Accepts printf-style format strings
138    //! - Outputs to UART hardware
139    //! - Is thread-safe (or only called from synchronized contexts)
140    //! - Returns number of characters written, or negative on error
141    
142    use core::ffi::{c_char, c_int};
143
144    unsafe extern "C" {
145        /// FFI function to print formatted strings to UART.
146        ///
147        /// This is the low-level C function that interfaces with the hardware UART.
148        /// Typically implemented in the platform-specific porting layer.
149        ///
150        /// # Safety
151        ///
152        /// - `format` must be a valid null-terminated C string
153        /// - Variable arguments must match the format specifiers
154        /// - Must not be called from multiple threads simultaneously (unless C implementation is thread-safe)
155        ///
156        /// # Parameters
157        ///
158        /// * `format` - Printf-style format string (null-terminated)
159        /// * `...` - Variable arguments matching format specifiers
160        ///
161        /// # Returns
162        ///
163        /// Number of characters written, or negative value on error
164        pub fn printf_on_uart(format: *const c_char, ...) -> c_int;
165
166    }
167}
168
169#[cfg(not(feature = "std"))]
170use core::ffi::c_char;
171
172#[cfg(not(feature = "std"))]
173use crate::log::ffi::printf_on_uart;
174use crate::os::{System, SystemFn};
175#[cfg(not(feature = "std"))]
176use crate::utils::Bytes;
177
178pub const LOG_BUFFER_SIZE: usize = 256;
179
180/// ANSI escape code for red text color
181const COLOR_RED: &str = "\x1b[31m";
182/// ANSI escape code for green text color
183const COLOR_GREEN: &str = "\x1b[32m";
184/// ANSI escape code for yellow text color
185const COLOR_YELLOW: &str = "\x1b[33m";
186/// ANSI escape code for blue text color
187#[allow(dead_code)]
188const COLOR_BLUE: &str = "\x1b[34m";
189/// ANSI escape code for magenta text color
190const COLOR_MAGENTA: &str = "\x1b[35m";
191/// ANSI escape code for cyan text color
192const COLOR_CYAN: &str = "\x1b[36m";
193/// ANSI escape code to reset all text attributes
194const COLOR_RESET: &str = "\x1b[0m";
195/// Carriage return + line feed for proper terminal output
196pub const RETURN: &str = "\r\n";
197
198/// Log level flags and level configurations.
199///
200/// This module defines bit flags for different log levels and combined
201/// level masks for filtering log messages.
202///
203/// # Flag vs Level
204///
205/// - **FLAGS** (`FLAG_*`): Individual bits for each log level, used internally
206/// - **LEVELS** (`LEVEL_*`): Combined masks that include all levels at or above the specified severity
207///
208/// For example, `LEVEL_WARNING` includes WARNING, ERROR, and FATAL flags.
209///
210/// # Usage
211///
212/// ```ignore
213/// use osal_rs::log::log_levels::*;
214/// use osal_rs::log::set_level_log;
215///
216/// // Set minimum level to WARNING (shows WARNING, ERROR, FATAL)
217/// set_level_log(LEVEL_WARNING);
218///
219/// // Check if specific level is enabled
220/// if is_enabled_log(FLAG_DEBUG) {
221///     // Debug is enabled
222/// }
223/// ```
224pub mod log_levels {
225    /// Flag for DEBUG level messages (bit 0, most verbose).
226    ///
227    /// Use for detailed debugging information during development.
228    pub const FLAG_DEBUG: u8 = 1 << 0;
229    
230    /// Flag for INFO level messages (bit 1).
231    ///
232    /// Use for informational messages about normal operation.
233    pub const FLAG_INFO: u8 = 1 << 1;
234    
235    /// Flag for WARNING level messages (bit 2).
236    ///
237    /// Use for potentially problematic situations that don't prevent operation.
238    pub const FLAG_WARNING: u8 = 1 << 2;
239    
240    /// Flag for ERROR level messages (bit 3).
241    ///
242    /// Use for errors that affect functionality but allow continued operation.
243    pub const FLAG_ERROR: u8 = 1 << 3;
244    
245    /// Flag for FATAL level messages (bit 4, most severe).
246    ///
247    /// Use for critical errors that prevent continued operation.
248    pub const FLAG_FATAL: u8 = 1 << 4;
249    
250    /// Flag to enable color output (bit 6).
251    ///
252    /// When set, log messages are color-coded by severity level.
253    pub const FLAG_COLOR_ON: u8 = 1 << 6;
254    
255    /// Flag to enable/disable logging entirely (bit 7).
256    ///
257    /// When clear, all logging is disabled for zero runtime cost.
258    pub const FLAG_STATE_ON: u8 = 1 << 7;
259
260    /// DEBUG level: Shows all messages (DEBUG, INFO, WARNING, ERROR, FATAL).
261    ///
262    /// Most verbose setting, suitable for development and troubleshooting.
263    pub const LEVEL_DEBUG: u8 = FLAG_DEBUG | FLAG_INFO | FLAG_WARNING | FLAG_ERROR | FLAG_FATAL;
264    
265    /// INFO level: Shows INFO and above (INFO, WARNING, ERROR, FATAL).
266    ///
267    /// Filters out DEBUG messages, suitable for normal operation.
268    pub const LEVEL_INFO: u8 = FLAG_INFO | FLAG_WARNING | FLAG_ERROR | FLAG_FATAL;
269    
270    /// WARNING level: Shows WARNING and above (WARNING, ERROR, FATAL).
271    ///
272    /// Shows only warnings and errors, suitable for production.
273    pub const LEVEL_WARNING: u8 = FLAG_WARNING | FLAG_ERROR | FLAG_FATAL;
274    
275    /// ERROR level: Shows ERROR and FATAL only.
276    ///
277    /// Shows only errors and critical failures.
278    pub const LEVEL_ERROR: u8 = FLAG_ERROR | FLAG_FATAL;
279
280    /// FATAL level: Shows only FATAL messages.
281    ///
282    /// Most restrictive setting, shows only critical failures.
283    pub const LEVEL_FATAL: u8 = FLAG_FATAL;
284}
285
286/// Global log level mask with color and state flags enabled by default.
287///
288/// This mutable static holds the current logging configuration:
289/// - Bits 0-4: Log level flags (DEBUG, INFO, WARNING, ERROR, FATAL)
290/// - Bit 6: Color enable flag
291/// - Bit 7: Logging enable/disable flag
292///
293/// # Default
294///
295/// Initialized to `LEVEL_DEBUG | FLAG_COLOR_ON | FLAG_STATE_ON`:
296/// - All log levels enabled
297/// - Color output enabled
298/// - Logging enabled
299///
300/// # Thread Safety
301///
302/// Modifications are not atomic. Use the provided setter functions
303/// (`set_level_log`, `set_enable_log`, `set_enable_color`) which perform
304/// simple bit operations that are effectively atomic on most platforms.
305/// Race conditions during initialization are unlikely to cause issues
306/// beyond temporarily incorrect filter settings.
307static mut MASK: u8 = log_levels::LEVEL_DEBUG | log_levels::FLAG_COLOR_ON | log_levels::FLAG_STATE_ON;
308
309/// Simple busy flag for thread-safe logging (0 = free, non-zero = busy).
310///
311/// Used as a spinlock to ensure only one thread logs at a time:
312/// - 0 = Lock is free, logging available
313/// - Non-zero = Lock is held, other threads must wait
314///
315/// # Synchronization
316///
317/// Uses a basic busy-wait (spinlock) pattern:
318/// 1. Wait until BUSY == 0
319/// 2. Set BUSY = 1
320/// 3. Perform logging
321/// 4. Set BUSY = 0
322///
323/// # Limitations
324///
325/// - Not a true atomic operation (no memory barriers)
326/// - Priority inversion possible (low-priority task holds lock)
327/// - Wastes CPU cycles during contention
328/// - **Never use from ISR context** - can deadlock
329///
330/// This simple approach is sufficient for most embedded use cases where
331/// logging contention is infrequent.
332static mut BUSY: u8 = 0;
333
334/// Prints formatted text without a newline.
335///
336/// In `std` mode this writes to standard output. In `no_std` mode this writes to UART.
337///
338/// # Examples
339///
340/// ```ignore
341/// use osal_rs::print;
342/// 
343/// print!("Hello");
344/// print!(" World: {}", 42);
345/// ```
346#[macro_export]
347macro_rules! print {
348    ($($arg:tt)*) => {{
349        $crate::log::print_args(format_args!($($arg)*));
350    }};
351}
352
353/// Prints formatted text with a newline (`\r\n`).
354///
355/// In `std` mode this writes to standard output. In `no_std` mode this writes to UART.
356///
357/// # Examples
358///
359/// ```ignore
360/// use osal_rs::println;
361/// 
362/// println!("Hello World");
363/// println!("Value: {}", 42);
364/// println!();  // Just a newline
365/// ```
366#[macro_export]
367macro_rules! println {
368    () => {{
369        $crate::log::print_newline();
370    }};
371    ($fmt:expr) => {{
372        $crate::log::print_args(format_args!(concat!($fmt, "\r\n")));
373    }};
374    ($fmt:expr, $($arg:tt)*) => {{
375        $crate::log::print_args(format_args!(concat!($fmt, "\r\n"), $($arg)*));
376    }};
377}
378
379#[doc(hidden)]
380pub fn print_args(args: core::fmt::Arguments<'_>) {
381    #[cfg(feature = "std")]
382    {
383        std::print!("{}", args);
384    }
385
386    #[cfg(not(feature = "std"))]
387    unsafe {
388        let mut buf = crate::utils::Bytes::<{ LOG_BUFFER_SIZE }>::new();
389        buf.format(args);
390        ffi::printf_on_uart(
391            b"%s\0".as_ptr() as *const core::ffi::c_char,
392            buf.as_cstr().as_ptr(),
393        );
394    }
395}
396
397#[doc(hidden)]
398pub fn print_newline() {
399    #[cfg(feature = "std")]
400    {
401        std::print!("{}", RETURN);
402    }
403
404    #[cfg(not(feature = "std"))]
405    unsafe {
406        ffi::printf_on_uart(b"\r\n\0".as_ptr() as *const core::ffi::c_char);
407    }
408}
409
410/// Sets the log level threshold.
411///
412/// Only log messages at or above this level will be displayed.
413///
414/// # Parameters
415///
416/// * `level` - Log level (use constants from `log_levels` module)
417///
418/// # Examples
419///
420/// ```ignore
421/// use osal_rs::log::*;
422/// 
423/// // Show only warnings and errors
424/// set_level_log(log_levels::LEVEL_WARNING);
425/// 
426/// // Show all messages
427/// set_level_log(log_levels::LEVEL_DEBUG);
428/// ```
429pub fn set_level_log(level: u8) {
430    unsafe {
431        MASK =
432            (MASK & log_levels::FLAG_STATE_ON) | (level & !log_levels::FLAG_STATE_ON);
433    }
434}
435
436/// Enables or disables all logging.
437///
438/// When disabled, all log macros become no-ops for zero runtime cost.
439///
440/// # Parameters
441///
442/// * `enabled` - `true` to enable logging, `false` to disable
443///
444/// # Examples
445///
446/// ```ignore
447/// use osal_rs::log::set_enable_log;
448/// 
449/// set_enable_log(false);  // Disable all logging
450/// // ... logs will not be printed ...
451/// set_enable_log(true);   // Re-enable logging
452/// ```
453pub fn set_enable_log(enabled: bool) {
454    unsafe {
455        if enabled {
456            MASK |= log_levels::FLAG_STATE_ON;
457        } else {
458            MASK &= !log_levels::FLAG_STATE_ON;
459        }
460    }
461}
462
463/// Checks if logging is currently enabled.
464///
465/// # Returns
466///
467/// `true` if logging is enabled, `false` otherwise
468///
469/// # Examples
470///
471/// ```ignore
472/// use osal_rs::log::get_enable_log;
473/// 
474/// if get_enable_log() {
475///     println!("Logging is active");
476/// }
477/// ```
478pub fn get_enable_log() -> bool {
479    unsafe { (MASK & log_levels::FLAG_STATE_ON) != 0 }
480}
481
482/// Checks if a specific log level is enabled.
483///
484/// # Parameters
485///
486/// * `log_type` - Log level flag to check
487///
488/// # Returns
489///
490/// `true` if the log level is enabled, `false` otherwise
491///
492/// # Examples
493///
494/// ```ignore
495/// use osal_rs::log::*;
496/// 
497/// if is_enabled_log(log_levels::FLAG_DEBUG) {
498///     // Debug logging is active
499/// }
500/// ```
501pub fn is_enabled_log(log_type: u8) -> bool {
502    unsafe { (MASK & log_levels::FLAG_STATE_ON) != 0 && (MASK & log_type) != 0 }
503}
504
505/// Gets the current log level threshold.
506///
507/// # Returns
508///
509/// Current log level mask (without state and color flags)
510///
511/// # Examples
512///
513/// ```ignore
514/// use osal_rs::log::*;
515/// 
516/// let level = get_level_log();
517/// ```
518pub fn get_level_log() -> u8 {
519    unsafe { MASK & !log_levels::FLAG_STATE_ON & !log_levels::FLAG_COLOR_ON }
520}
521
522/// Enables or disables color output.
523///
524/// When enabled, log messages are color-coded by severity:
525/// - DEBUG: Cyan
526/// - INFO: Green  
527/// - WARNING: Yellow
528/// - ERROR: Red
529/// - FATAL: Magenta
530///
531/// # Parameters
532///
533/// * `enabled` - `true` to enable colors, `false` for plain text
534///
535/// # Examples
536///
537/// ```ignore
538/// use osal_rs::log::set_enable_color;
539/// 
540/// set_enable_color(true);   // Enable colored output
541/// set_enable_color(false);  // Disable colors
542/// ```
543pub fn set_enable_color(enabled: bool) {
544    unsafe {
545        if enabled {
546            MASK |= log_levels::FLAG_COLOR_ON;
547        } else {
548            MASK &= !log_levels::FLAG_COLOR_ON;
549        }
550    }
551}
552
553
554
555/// Core logging function that outputs formatted log messages.
556///
557/// This is the low-level function called by all log macros. It handles:
558/// - Thread-safe output using a busy-wait lock
559/// - Color formatting based on log level
560/// - Timestamp prefixing with millisecond precision
561/// - Tag prefixing for message categorization
562///
563/// # Parameters
564///
565/// * `tag` - Category or module name for the log message (e.g., "APP", "NET", "FS")
566/// * `log_type` - Log level flag (DEBUG, INFO, WARNING, ERROR, FATAL)
567/// * `to_print` - The formatted message string to log
568///
569/// # Thread Safety
570///
571/// Uses a busy-wait lock (BUSY flag) to ensure only one thread logs at a time:
572/// 1. Spins until BUSY == 0
573/// 2. Sets BUSY = 1
574/// 3. Formats and outputs the message
575/// 4. Sets BUSY = 0
576///
577/// Other threads will spin-wait during this time.
578///
579/// # Output Format
580///
581/// In `no_std` mode:
582/// ```text
583/// {color}({timestamp}ms)[{tag}] {message}{color_reset}\r\n
584/// ```
585///
586/// Example:
587/// ```text
588/// \x1b[32m(1234ms)[APP] System initialized\x1b[0m\r\n
589/// ```
590///
591/// # Examples
592///
593/// ```ignore
594/// use osal_rs::log::*;
595/// 
596/// sys_log("APP", log_levels::FLAG_INFO, "Application started");
597/// sys_log("NET", log_levels::FLAG_ERROR, "Connection failed");
598/// ```
599///
600/// # Note
601///
602/// Prefer using the log macros (`log_info!`, `log_error!`, etc.) instead of
603/// calling this function directly. The macros check if the log level is enabled
604/// before formatting the message, avoiding allocation for disabled levels.
605///
606/// # Warning
607///
608/// **Never call from ISR context** - the busy-wait can cause deadlock if a
609/// higher-priority ISR preempts a task that holds the lock.
610pub fn sys_log(tag: &str, log_type: u8, to_print: &str) {
611    unsafe {
612        while BUSY != 0 {}
613        BUSY = 1;
614
615        let mut color_reset = COLOR_RESET;
616        let color = if MASK & log_levels::FLAG_COLOR_ON == log_levels::FLAG_COLOR_ON {
617
618            match log_type {
619                log_levels::FLAG_DEBUG => COLOR_CYAN,
620                log_levels::FLAG_INFO => COLOR_GREEN,
621                log_levels::FLAG_WARNING => COLOR_YELLOW,
622                log_levels::FLAG_ERROR => COLOR_RED,
623                log_levels::FLAG_FATAL => COLOR_MAGENTA,
624                _ => COLOR_RESET,
625            }
626        } else {
627            color_reset = "";
628            ""
629        };
630
631
632        let now = System::get_current_time_us();
633
634
635        #[cfg(not(feature = "std"))]
636        {
637            let mut buf = Bytes::<512>::new();
638            buf.format(format_args!("{color}({millis}ms)[{tag}] {to_print}{color_reset}{RETURN}", millis=now.as_millis()));
639            printf_on_uart(b"%s\0".as_ptr() as *const c_char, buf.as_cstr().as_ptr());
640        }
641
642        #[cfg(feature = "std")]
643        {
644            std::println!("{color}({}ms)[{tag}] {to_print}{color_reset}", now.as_millis());
645        }
646
647        BUSY = 0;
648    }
649}
650
651/// Logs a DEBUG level message.
652///
653/// Debug messages are the most verbose and typically used during development.
654/// Color: Cyan (if colors are enabled)
655///
656/// # Parameters
657///
658/// * `app_tag` - Category or module identifier
659/// * `fmt` - Format string
660/// * `arg` - Optional format arguments
661///
662/// # Examples
663///
664/// ```ignore
665/// use osal_rs::log_debug;
666/// 
667/// log_debug!("APP", "Initializing subsystem");
668/// log_debug!("APP", "Counter: {}, Status: {}", counter, status);
669/// ```
670#[macro_export]
671macro_rules! log_debug {
672    ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
673        if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_DEBUG) {
674            let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
675            msg.format(format_args!($fmt $(, $($arg)*)?));
676            $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_DEBUG, msg.as_str());
677        }
678    }};
679}
680
681/// Logs an INFO level message.
682///
683/// Informational messages about normal application operation.
684/// Color: Green (if colors are enabled)
685///
686/// # Parameters
687///
688/// * `app_tag` - Category or module identifier
689/// * `fmt` - Format string  
690/// * `arg` - Optional format arguments
691///
692/// # Examples
693///
694/// ```ignore
695/// use osal_rs::log_info;
696/// 
697/// log_info!("APP", "System initialized successfully");
698/// log_info!("NET", "Connected to server at {}", ip_addr);
699/// ```
700#[macro_export]
701macro_rules! log_info {
702    ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
703        if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_INFO) {
704            let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
705            msg.format(format_args!($fmt $(, $($arg)*)?));
706            $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_INFO, msg.as_str());
707        }
708    }};
709}
710
711/// Logs a WARNING level message.
712///
713/// Warning messages indicate potential issues that don't prevent operation.
714/// Color: Yellow (if colors are enabled)
715///
716/// # Parameters
717///
718/// * `app_tag` - Category or module identifier
719/// * `fmt` - Format string
720/// * `arg` - Optional format arguments
721///
722/// # Examples
723///
724/// ```ignore
725/// use osal_rs::log_warning;
726/// 
727/// log_warning!("MEM", "Memory usage above 80%");
728/// log_warning!("SENSOR", "Temperature high: {} C", temp);
729/// ```
730#[macro_export]
731macro_rules! log_warning {
732    ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
733        if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_WARNING) {
734            let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
735            msg.format(format_args!($fmt $(, $($arg)*)?));
736            $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_WARNING, msg.as_str());
737        }
738    }};
739}
740
741/// Logs an ERROR level message.
742///
743/// Error messages indicate failures that affect functionality.
744/// Color: Red (if colors are enabled)
745///
746/// # Parameters
747///
748/// * `app_tag` - Category or module identifier
749/// * `fmt` - Format string
750/// * `arg` - Optional format arguments
751///
752/// # Examples
753///
754/// ```ignore
755/// use osal_rs::log_error;
756/// 
757/// log_error!("FS", "Failed to open file");
758/// log_error!("NET", "Connection timeout: {}", error);
759/// ```
760#[macro_export]
761macro_rules! log_error {
762    ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
763        if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_ERROR) {
764            let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
765            msg.format(format_args!($fmt $(, $($arg)*)?));
766            $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_ERROR, msg.as_str());
767        }
768    }};
769}
770
771/// Logs a FATAL level message.
772///
773/// Fatal messages indicate critical errors that prevent continued operation.
774/// Color: Magenta (if colors are enabled)
775///
776/// # Parameters
777///
778/// * `app_tag` - Category or module identifier
779/// * `fmt` - Format string
780/// * `arg` - Optional format arguments
781///
782/// # Examples
783///
784/// ```ignore
785/// use osal_rs::log_fatal;
786/// 
787/// log_fatal!("SYS", "Kernel panic!");
788/// log_fatal!("HW", "Hardware fault detected: {}", fault_code);
789/// ```
790#[macro_export]
791macro_rules! log_fatal {
792    ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
793        if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_FATAL) {
794            let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
795            msg.format(format_args!($fmt $(, $($arg)*)?));
796            $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_FATAL, msg.as_str());
797        }
798    }};
799}