Skip to main content

coreshift_core/log/
mod.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/
4
5//! Backend-agnostic logging facade.
6
7mod android;
8mod null;
9mod stderr;
10
11/// Log severity levels.
12#[repr(i32)]
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum LogLevel {
15    Verbose = 2,
16    Debug = 3,
17    Info = 4,
18    Warn = 5,
19    Error = 6,
20    Fatal = 7,
21}
22
23/// Legacy alias for [`LogLevel`].
24pub type LogPriority = LogLevel;
25
26/// Available logging backends.
27#[repr(u8)]
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub enum LogBackend {
30    /// Android system log (liblog).
31    Android = 0,
32    /// Standard error.
33    Stderr = 1,
34    /// Discard all messages.
35    Null = 2,
36}
37
38/// A handle for writing messages to a specific log backend.
39///
40/// Core follows a "no global mutable state" architecture. Callers that require
41/// a non-default logging backend must create a [`Logger`] instance and use
42/// it directly.
43///
44/// By default, macros like `alog_info!` use a platform-appropriate default
45/// logger ([`LogBackend::Android`] on Android, [`LogBackend::Stderr`] otherwise).
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub struct Logger {
48    backend: LogBackend,
49}
50
51impl Default for Logger {
52    fn default() -> Self {
53        #[cfg(target_os = "android")]
54        {
55            Self::new(LogBackend::Android)
56        }
57        #[cfg(not(target_os = "android"))]
58        {
59            Self::new(LogBackend::Stderr)
60        }
61    }
62}
63
64impl Logger {
65    /// Create a new logger with the specified backend.
66    pub fn new(backend: LogBackend) -> Self {
67        Self { backend }
68    }
69
70    /// Write a message to the logger's active backend.
71    pub fn log(&self, level: LogLevel, tag: &str, msg: &str) {
72        match self.backend {
73            LogBackend::Android => android::log(level, tag, msg),
74            LogBackend::Stderr => stderr::log(level, tag, msg),
75            LogBackend::Null => null::log(level, tag, msg),
76        }
77    }
78}
79
80/// Write a message using the platform default logger.
81///
82/// In release builds (`debug_assertions` off), Verbose/Debug/Info/Warn are
83/// stripped. Error and Fatal always emit regardless of build profile.
84pub fn log(level: LogLevel, tag: &str, msg: &str) {
85    #[cfg(not(debug_assertions))]
86    if (level as i32) < (LogLevel::Error as i32) {
87        return;
88    }
89    #[cfg(target_os = "android")]
90    {
91        android::log(level, tag, msg);
92    }
93    #[cfg(not(target_os = "android"))]
94    {
95        stderr::log(level, tag, msg);
96    }
97}
98
99/// Legacy alias for [`log`].
100pub fn log_write(level: LogLevel, tag: &str, msg: &str) {
101    log(level, tag, msg);
102}
103
104#[macro_export]
105macro_rules! alog_verbose {
106    ($tag:expr, $($arg:tt)*) => {
107        $crate::log::log($crate::log::LogLevel::Verbose, $tag, &format!($($arg)*))
108    };
109    ($tag:expr) => {
110        $crate::log::log($crate::log::LogLevel::Verbose, $tag, "")
111    };
112}
113
114#[macro_export]
115macro_rules! alog_debug {
116    ($tag:expr, $($arg:tt)*) => {
117        $crate::log::log($crate::log::LogLevel::Debug, $tag, &format!($($arg)*))
118    };
119    ($tag:expr) => {
120        $crate::log::log($crate::log::LogLevel::Debug, $tag, "")
121    };
122}
123
124#[macro_export]
125macro_rules! alog_info {
126    ($tag:expr, $($arg:tt)*) => {
127        $crate::log::log($crate::log::LogLevel::Info, $tag, &format!($($arg)*))
128    };
129    ($tag:expr) => {
130        $crate::log::log($crate::log::LogLevel::Info, $tag, "")
131    };
132}
133
134#[macro_export]
135macro_rules! alog_warn {
136    ($tag:expr, $($arg:tt)*) => {
137        $crate::log::log($crate::log::LogLevel::Warn, $tag, &format!($($arg)*))
138    };
139    ($tag:expr) => {
140        $crate::log::log($crate::log::LogLevel::Warn, $tag, "")
141    };
142}
143
144#[macro_export]
145macro_rules! alog_error {
146    ($tag:expr, $($arg:tt)*) => {
147        $crate::log::log($crate::log::LogLevel::Error, $tag, &format!($($arg)*))
148    };
149    ($tag:expr) => {
150        $crate::log::log($crate::log::LogLevel::Error, $tag, "")
151    };
152}
153
154#[macro_export]
155macro_rules! alog_fatal {
156    ($tag:expr, $($arg:tt)*) => {
157        $crate::log::log($crate::log::LogLevel::Fatal, $tag, &format!($($arg)*))
158    };
159    ($tag:expr) => {
160        $crate::log::log($crate::log::LogLevel::Fatal, $tag, "")
161    };
162}
163
164#[macro_export]
165macro_rules! log_verbose {
166    ($tag:expr, $($arg:tt)*) => {
167        $crate::log::log($crate::log::LogLevel::Verbose, $tag, &format!($($arg)*))
168    };
169    ($tag:expr) => {
170        $crate::log::log($crate::log::LogLevel::Verbose, $tag, "")
171    };
172}
173
174#[macro_export]
175macro_rules! log_debug {
176    ($tag:expr, $($arg:tt)*) => {
177        $crate::log::log($crate::log::LogLevel::Debug, $tag, &format!($($arg)*))
178    };
179    ($tag:expr) => {
180        $crate::log::log($crate::log::LogLevel::Debug, $tag, "")
181    };
182}
183
184#[macro_export]
185macro_rules! log_info {
186    ($tag:expr, $($arg:tt)*) => {
187        $crate::log::log($crate::log::LogLevel::Info, $tag, &format!($($arg)*))
188    };
189    ($tag:expr) => {
190        $crate::log::log($crate::log::LogLevel::Info, $tag, "")
191    };
192}
193
194#[macro_export]
195macro_rules! log_warn {
196    ($tag:expr, $($arg:tt)*) => {
197        $crate::log::log($crate::log::LogLevel::Warn, $tag, &format!($($arg)*))
198    };
199    ($tag:expr) => {
200        $crate::log::log($crate::log::LogLevel::Warn, $tag, "")
201    };
202}
203
204#[macro_export]
205macro_rules! log_error {
206    ($tag:expr, $($arg:tt)*) => {
207        $crate::log::log($crate::log::LogLevel::Error, $tag, &format!($($arg)*))
208    };
209    ($tag:expr) => {
210        $crate::log::log($crate::log::LogLevel::Error, $tag, "")
211    };
212}
213
214#[macro_export]
215macro_rules! log_fatal {
216    ($tag:expr, $($arg:tt)*) => {
217        $crate::log::log($crate::log::LogLevel::Fatal, $tag, &format!($($arg)*))
218    };
219    ($tag:expr) => {
220        $crate::log::log($crate::log::LogLevel::Fatal, $tag, "")
221    };
222}