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
169use core::ffi::c_char;
170
171use crate::log::ffi::printf_on_uart;
172use crate::os::{System, SystemFn};
173use crate::utils::Bytes;
174
175pub const LOG_BUFFER_SIZE: usize = 256;
176
177/// ANSI escape code for red text color
178const COLOR_RED: &str = "\x1b[31m";
179/// ANSI escape code for green text color
180const COLOR_GREEN: &str = "\x1b[32m";
181/// ANSI escape code for yellow text color
182const COLOR_YELLOW: &str = "\x1b[33m";
183/// ANSI escape code for blue text color
184const COLOR_BLUE: &str = "\x1b[34m";
185/// ANSI escape code for magenta text color
186const COLOR_MAGENTA: &str = "\x1b[35m";
187/// ANSI escape code for cyan text color
188const COLOR_CYAN: &str = "\x1b[36m";
189/// ANSI escape code to reset all text attributes
190const COLOR_RESET: &str = "\x1b[0m";
191/// Carriage return + line feed for proper terminal output
192pub const RETURN: &str = "\r\n";
193
194/// Log level flags and level configurations.
195///
196/// This module defines bit flags for different log levels and combined
197/// level masks for filtering log messages.
198///
199/// # Flag vs Level
200///
201/// - **FLAGS** (`FLAG_*`): Individual bits for each log level, used internally
202/// - **LEVELS** (`LEVEL_*`): Combined masks that include all levels at or above the specified severity
203///
204/// For example, `LEVEL_WARNING` includes WARNING, ERROR, and FATAL flags.
205///
206/// # Usage
207///
208/// ```ignore
209/// use osal_rs::log::log_levels::*;
210/// use osal_rs::log::set_level_log;
211///
212/// // Set minimum level to WARNING (shows WARNING, ERROR, FATAL)
213/// set_level_log(LEVEL_WARNING);
214///
215/// // Check if specific level is enabled
216/// if is_enabled_log(FLAG_DEBUG) {
217/// // Debug is enabled
218/// }
219/// ```
220pub mod log_levels {
221 /// Flag for DEBUG level messages (bit 0, most verbose).
222 ///
223 /// Use for detailed debugging information during development.
224 pub const FLAG_DEBUG: u8 = 1 << 0;
225
226 /// Flag for INFO level messages (bit 1).
227 ///
228 /// Use for informational messages about normal operation.
229 pub const FLAG_INFO: u8 = 1 << 1;
230
231 /// Flag for WARNING level messages (bit 2).
232 ///
233 /// Use for potentially problematic situations that don't prevent operation.
234 pub const FLAG_WARNING: u8 = 1 << 2;
235
236 /// Flag for ERROR level messages (bit 3).
237 ///
238 /// Use for errors that affect functionality but allow continued operation.
239 pub const FLAG_ERROR: u8 = 1 << 3;
240
241 /// Flag for FATAL level messages (bit 4, most severe).
242 ///
243 /// Use for critical errors that prevent continued operation.
244 pub const FLAG_FATAL: u8 = 1 << 4;
245
246 /// Flag to enable color output (bit 6).
247 ///
248 /// When set, log messages are color-coded by severity level.
249 pub const FLAG_COLOR_ON: u8 = 1 << 6;
250
251 /// Flag to enable/disable logging entirely (bit 7).
252 ///
253 /// When clear, all logging is disabled for zero runtime cost.
254 pub const FLAG_STATE_ON: u8 = 1 << 7;
255
256 /// DEBUG level: Shows all messages (DEBUG, INFO, WARNING, ERROR, FATAL).
257 ///
258 /// Most verbose setting, suitable for development and troubleshooting.
259 pub const LEVEL_DEBUG: u8 = FLAG_DEBUG | FLAG_INFO | FLAG_WARNING | FLAG_ERROR | FLAG_FATAL;
260
261 /// INFO level: Shows INFO and above (INFO, WARNING, ERROR, FATAL).
262 ///
263 /// Filters out DEBUG messages, suitable for normal operation.
264 pub const LEVEL_INFO: u8 = FLAG_INFO | FLAG_WARNING | FLAG_ERROR | FLAG_FATAL;
265
266 /// WARNING level: Shows WARNING and above (WARNING, ERROR, FATAL).
267 ///
268 /// Shows only warnings and errors, suitable for production.
269 pub const LEVEL_WARNING: u8 = FLAG_WARNING | FLAG_ERROR | FLAG_FATAL;
270
271 /// ERROR level: Shows ERROR and FATAL only.
272 ///
273 /// Shows only errors and critical failures.
274 pub const LEVEL_ERROR: u8 = FLAG_ERROR | FLAG_FATAL;
275
276 /// FATAL level: Shows only FATAL messages.
277 ///
278 /// Most restrictive setting, shows only critical failures.
279 pub const LEVEL_FATAL: u8 = FLAG_FATAL;
280}
281
282/// Global log level mask with color and state flags enabled by default.
283///
284/// This mutable static holds the current logging configuration:
285/// - Bits 0-4: Log level flags (DEBUG, INFO, WARNING, ERROR, FATAL)
286/// - Bit 6: Color enable flag
287/// - Bit 7: Logging enable/disable flag
288///
289/// # Default
290///
291/// Initialized to `LEVEL_DEBUG | FLAG_COLOR_ON | FLAG_STATE_ON`:
292/// - All log levels enabled
293/// - Color output enabled
294/// - Logging enabled
295///
296/// # Thread Safety
297///
298/// Modifications are not atomic. Use the provided setter functions
299/// (`set_level_log`, `set_enable_log`, `set_enable_color`) which perform
300/// simple bit operations that are effectively atomic on most platforms.
301/// Race conditions during initialization are unlikely to cause issues
302/// beyond temporarily incorrect filter settings.
303static mut MASK: u8 = log_levels::LEVEL_DEBUG | log_levels::FLAG_COLOR_ON | log_levels::FLAG_STATE_ON;
304
305/// Simple busy flag for thread-safe logging (0 = free, non-zero = busy).
306///
307/// Used as a spinlock to ensure only one thread logs at a time:
308/// - 0 = Lock is free, logging available
309/// - Non-zero = Lock is held, other threads must wait
310///
311/// # Synchronization
312///
313/// Uses a basic busy-wait (spinlock) pattern:
314/// 1. Wait until BUSY == 0
315/// 2. Set BUSY = 1
316/// 3. Perform logging
317/// 4. Set BUSY = 0
318///
319/// # Limitations
320///
321/// - Not a true atomic operation (no memory barriers)
322/// - Priority inversion possible (low-priority task holds lock)
323/// - Wastes CPU cycles during contention
324/// - **Never use from ISR context** - can deadlock
325///
326/// This simple approach is sufficient for most embedded use cases where
327/// logging contention is infrequent.
328static mut BUSY: u8 = 0;
329
330/// Prints formatted text to UART without a newline.
331///
332/// This macro is only available in no-std mode. In std mode, use the standard `print!` macro.
333///
334/// # Examples
335///
336/// ```ignore
337/// use osal_rs::print;
338///
339/// print!("Hello");
340/// print!(" World: {}", 42);
341/// ```
342#[cfg(not(feature = "std"))]
343#[macro_export]
344macro_rules! print {
345 ($($arg:tt)*) => {{
346 unsafe {
347 let mut buf = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
348 buf.format(format_args!($($arg)*));
349 $crate::log::ffi::printf_on_uart(b"%s\0".as_ptr() as *const core::ffi::c_char, buf.as_cstr().as_ptr());
350 }
351 }};
352}
353
354/// Prints formatted text to UART with a newline (\r\n).
355///
356/// This macro is only available in no-std mode. In std mode, use the standard `println!` macro.
357///
358/// # Examples
359///
360/// ```ignore
361/// use osal_rs::println;
362///
363/// println!("Hello World");
364/// println!("Value: {}", 42);
365/// println!(); // Just a newline
366/// ```
367#[cfg(not(feature = "std"))]
368#[macro_export]
369macro_rules! println {
370 () => {
371 $crate::print!("\r\n")
372 };
373 ($fmt:expr) => {{
374 unsafe {
375 let mut buf = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
376 buf.format(format_args!(concat!($fmt, "\r\n")));
377 $crate::log::ffi::printf_on_uart(b"%s\0".as_ptr() as *const core::ffi::c_char, buf.as_cstr().as_ptr());
378 }
379 }};
380 ($fmt:expr, $($arg:tt)*) => {{
381 unsafe {
382 let mut buf = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
383 buf.format(format_args!(concat!($fmt, "\r\n"), $($arg)*));
384 $crate::log::ffi::printf_on_uart(b"%s\0".as_ptr() as *const core::ffi::c_char, buf.as_cstr().as_ptr());
385 }
386 }};
387}
388
389/// Sets the log level threshold.
390///
391/// Only log messages at or above this level will be displayed.
392///
393/// # Parameters
394///
395/// * `level` - Log level (use constants from `log_levels` module)
396///
397/// # Examples
398///
399/// ```ignore
400/// use osal_rs::log::*;
401///
402/// // Show only warnings and errors
403/// set_level_log(log_levels::LEVEL_WARNING);
404///
405/// // Show all messages
406/// set_level_log(log_levels::LEVEL_DEBUG);
407/// ```
408pub fn set_level_log(level: u8) {
409 unsafe {
410 MASK =
411 (MASK & log_levels::FLAG_STATE_ON) | (level & !log_levels::FLAG_STATE_ON);
412 }
413}
414
415/// Enables or disables all logging.
416///
417/// When disabled, all log macros become no-ops for zero runtime cost.
418///
419/// # Parameters
420///
421/// * `enabled` - `true` to enable logging, `false` to disable
422///
423/// # Examples
424///
425/// ```ignore
426/// use osal_rs::log::set_enable_log;
427///
428/// set_enable_log(false); // Disable all logging
429/// // ... logs will not be printed ...
430/// set_enable_log(true); // Re-enable logging
431/// ```
432pub fn set_enable_log(enabled: bool) {
433 unsafe {
434 if enabled {
435 MASK |= log_levels::FLAG_STATE_ON;
436 } else {
437 MASK &= !log_levels::FLAG_STATE_ON;
438 }
439 }
440}
441
442/// Checks if logging is currently enabled.
443///
444/// # Returns
445///
446/// `true` if logging is enabled, `false` otherwise
447///
448/// # Examples
449///
450/// ```ignore
451/// use osal_rs::log::get_enable_log;
452///
453/// if get_enable_log() {
454/// println!("Logging is active");
455/// }
456/// ```
457pub fn get_enable_log() -> bool {
458 unsafe { (MASK & log_levels::FLAG_STATE_ON) != 0 }
459}
460
461/// Checks if a specific log level is enabled.
462///
463/// # Parameters
464///
465/// * `log_type` - Log level flag to check
466///
467/// # Returns
468///
469/// `true` if the log level is enabled, `false` otherwise
470///
471/// # Examples
472///
473/// ```ignore
474/// use osal_rs::log::*;
475///
476/// if is_enabled_log(log_levels::FLAG_DEBUG) {
477/// // Debug logging is active
478/// }
479/// ```
480pub fn is_enabled_log(log_type: u8) -> bool {
481 unsafe { (MASK & log_levels::FLAG_STATE_ON) != 0 && (MASK & log_type) != 0 }
482}
483
484/// Gets the current log level threshold.
485///
486/// # Returns
487///
488/// Current log level mask (without state and color flags)
489///
490/// # Examples
491///
492/// ```ignore
493/// use osal_rs::log::*;
494///
495/// let level = get_level_log();
496/// ```
497pub fn get_level_log() -> u8 {
498 unsafe { MASK & !log_levels::FLAG_STATE_ON & !log_levels::FLAG_COLOR_ON }
499}
500
501/// Enables or disables color output.
502///
503/// When enabled, log messages are color-coded by severity:
504/// - DEBUG: Cyan
505/// - INFO: Green
506/// - WARNING: Yellow
507/// - ERROR: Red
508/// - FATAL: Magenta
509///
510/// # Parameters
511///
512/// * `enabled` - `true` to enable colors, `false` for plain text
513///
514/// # Examples
515///
516/// ```ignore
517/// use osal_rs::log::set_enable_color;
518///
519/// set_enable_color(true); // Enable colored output
520/// set_enable_color(false); // Disable colors
521/// ```
522pub fn set_enable_color(enabled: bool) {
523 unsafe {
524 if enabled {
525 MASK |= log_levels::FLAG_COLOR_ON;
526 } else {
527 MASK &= !log_levels::FLAG_COLOR_ON;
528 }
529 }
530}
531
532
533
534/// Core logging function that outputs formatted log messages.
535///
536/// This is the low-level function called by all log macros. It handles:
537/// - Thread-safe output using a busy-wait lock
538/// - Color formatting based on log level
539/// - Timestamp prefixing with millisecond precision
540/// - Tag prefixing for message categorization
541///
542/// # Parameters
543///
544/// * `tag` - Category or module name for the log message (e.g., "APP", "NET", "FS")
545/// * `log_type` - Log level flag (DEBUG, INFO, WARNING, ERROR, FATAL)
546/// * `to_print` - The formatted message string to log
547///
548/// # Thread Safety
549///
550/// Uses a busy-wait lock (BUSY flag) to ensure only one thread logs at a time:
551/// 1. Spins until BUSY == 0
552/// 2. Sets BUSY = 1
553/// 3. Formats and outputs the message
554/// 4. Sets BUSY = 0
555///
556/// Other threads will spin-wait during this time.
557///
558/// # Output Format
559///
560/// In `no_std` mode:
561/// ```text
562/// {color}({timestamp}ms)[{tag}] {message}{color_reset}\r\n
563/// ```
564///
565/// Example:
566/// ```text
567/// \x1b[32m(1234ms)[APP] System initialized\x1b[0m\r\n
568/// ```
569///
570/// # Examples
571///
572/// ```ignore
573/// use osal_rs::log::*;
574///
575/// sys_log("APP", log_levels::FLAG_INFO, "Application started");
576/// sys_log("NET", log_levels::FLAG_ERROR, "Connection failed");
577/// ```
578///
579/// # Note
580///
581/// Prefer using the log macros (`log_info!`, `log_error!`, etc.) instead of
582/// calling this function directly. The macros check if the log level is enabled
583/// before formatting the message, avoiding allocation for disabled levels.
584///
585/// # Warning
586///
587/// **Never call from ISR context** - the busy-wait can cause deadlock if a
588/// higher-priority ISR preempts a task that holds the lock.
589pub fn sys_log(tag: &str, log_type: u8, to_print: &str) {
590 unsafe {
591 while BUSY != 0 {}
592 BUSY = 1;
593
594 let mut color_reset = COLOR_RESET;
595 let color = if MASK & log_levels::FLAG_COLOR_ON == log_levels::FLAG_COLOR_ON {
596
597 match log_type {
598 log_levels::FLAG_DEBUG => COLOR_CYAN,
599 log_levels::FLAG_INFO => COLOR_GREEN,
600 log_levels::FLAG_WARNING => COLOR_YELLOW,
601 log_levels::FLAG_ERROR => COLOR_RED,
602 log_levels::FLAG_FATAL => COLOR_MAGENTA,
603 _ => COLOR_RESET,
604 }
605 } else {
606 color_reset = "";
607 ""
608 };
609
610
611 let now = System::get_current_time_us();
612
613
614 #[cfg(not(feature = "std"))]
615 {
616 let mut buf = Bytes::<512>::new();
617 buf.format(format_args!("{color}({millis}ms)[{tag}] {to_print}{color_reset}{RETURN}", millis=now.as_millis()));
618 printf_on_uart(b"%s\0".as_ptr() as *const c_char, buf.as_cstr().as_ptr());
619 }
620
621 #[cfg(feature = "std")]
622 {
623 print!("{}[{}] ", color, tag);
624 core::fmt::write(&mut core::fmt::Formatter::new(), args).unwrap();
625 print!("{}", COLOR_RESET);
626 print!("\r\n");
627 }
628
629 BUSY = 0;
630 }
631}
632
633/// Logs a DEBUG level message.
634///
635/// Debug messages are the most verbose and typically used during development.
636/// Color: Cyan (if colors are enabled)
637///
638/// # Parameters
639///
640/// * `app_tag` - Category or module identifier
641/// * `fmt` - Format string
642/// * `arg` - Optional format arguments
643///
644/// # Examples
645///
646/// ```ignore
647/// use osal_rs::log_debug;
648///
649/// log_debug!("APP", "Initializing subsystem");
650/// log_debug!("APP", "Counter: {}, Status: {}", counter, status);
651/// ```
652#[macro_export]
653macro_rules! log_debug {
654 ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
655 if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_DEBUG) {
656 let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
657 msg.format(format_args!($fmt $(, $($arg)*)?));
658 $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_DEBUG, msg.as_str());
659 }
660 }};
661}
662
663/// Logs an INFO level message.
664///
665/// Informational messages about normal application operation.
666/// Color: Green (if colors are enabled)
667///
668/// # Parameters
669///
670/// * `app_tag` - Category or module identifier
671/// * `fmt` - Format string
672/// * `arg` - Optional format arguments
673///
674/// # Examples
675///
676/// ```ignore
677/// use osal_rs::log_info;
678///
679/// log_info!("APP", "System initialized successfully");
680/// log_info!("NET", "Connected to server at {}", ip_addr);
681/// ```
682#[macro_export]
683macro_rules! log_info {
684 ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
685 if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_INFO) {
686 let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
687 msg.format(format_args!($fmt $(, $($arg)*)?));
688 $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_INFO, msg.as_str());
689 }
690 }};
691}
692
693/// Logs a WARNING level message.
694///
695/// Warning messages indicate potential issues that don't prevent operation.
696/// Color: Yellow (if colors are enabled)
697///
698/// # Parameters
699///
700/// * `app_tag` - Category or module identifier
701/// * `fmt` - Format string
702/// * `arg` - Optional format arguments
703///
704/// # Examples
705///
706/// ```ignore
707/// use osal_rs::log_warning;
708///
709/// log_warning!("MEM", "Memory usage above 80%");
710/// log_warning!("SENSOR", "Temperature high: {} C", temp);
711/// ```
712#[macro_export]
713macro_rules! log_warning {
714 ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
715 if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_WARNING) {
716 let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
717 msg.format(format_args!($fmt $(, $($arg)*)?));
718 $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_WARNING, msg.as_str());
719 }
720 }};
721}
722
723/// Logs an ERROR level message.
724///
725/// Error messages indicate failures that affect functionality.
726/// Color: Red (if colors are enabled)
727///
728/// # Parameters
729///
730/// * `app_tag` - Category or module identifier
731/// * `fmt` - Format string
732/// * `arg` - Optional format arguments
733///
734/// # Examples
735///
736/// ```ignore
737/// use osal_rs::log_error;
738///
739/// log_error!("FS", "Failed to open file");
740/// log_error!("NET", "Connection timeout: {}", error);
741/// ```
742#[macro_export]
743macro_rules! log_error {
744 ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
745 if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_ERROR) {
746 let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
747 msg.format(format_args!($fmt $(, $($arg)*)?));
748 $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_ERROR, msg.as_str());
749 }
750 }};
751}
752
753/// Logs a FATAL level message.
754///
755/// Fatal messages indicate critical errors that prevent continued operation.
756/// Color: Magenta (if colors are enabled)
757///
758/// # Parameters
759///
760/// * `app_tag` - Category or module identifier
761/// * `fmt` - Format string
762/// * `arg` - Optional format arguments
763///
764/// # Examples
765///
766/// ```ignore
767/// use osal_rs::log_fatal;
768///
769/// log_fatal!("SYS", "Kernel panic!");
770/// log_fatal!("HW", "Hardware fault detected: {}", fault_code);
771/// ```
772#[macro_export]
773macro_rules! log_fatal {
774 ($app_tag:expr, $fmt:expr $(, $($arg:tt)*)?) => {{
775 if $crate::log::is_enabled_log($crate::log::log_levels::FLAG_FATAL) {
776 let mut msg = $crate::utils::Bytes::<{$crate::log::LOG_BUFFER_SIZE}>::new();
777 msg.format(format_args!($fmt $(, $($arg)*)?));
778 $crate::log::sys_log($app_tag, $crate::log::log_levels::FLAG_FATAL, msg.as_str());
779 }
780 }};
781}