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/// No-op in release builds (`debug_assertions` off). All `log_*` macros
83/// call this, so logging is stripped entirely from release binaries.
84pub fn log(level: LogLevel, tag: &str, msg: &str) {
85    #[cfg(debug_assertions)]
86    {
87        #[cfg(target_os = "android")]
88        { android::log(level, tag, msg); }
89        #[cfg(not(target_os = "android"))]
90        { stderr::log(level, tag, msg); }
91    }
92    #[cfg(not(debug_assertions))]
93    {
94        let _ = (level, tag, msg);
95    }
96}
97
98/// Legacy alias for [`log`].
99pub fn log_write(level: LogLevel, tag: &str, msg: &str) {
100    log(level, tag, msg);
101}
102
103#[macro_export]
104macro_rules! alog_verbose {
105    ($tag:expr, $($arg:tt)*) => {
106        $crate::log::log($crate::log::LogLevel::Verbose, $tag, &format!($($arg)*))
107    };
108    ($tag:expr) => {
109        $crate::log::log($crate::log::LogLevel::Verbose, $tag, "")
110    };
111}
112
113#[macro_export]
114macro_rules! alog_debug {
115    ($tag:expr, $($arg:tt)*) => {
116        $crate::log::log($crate::log::LogLevel::Debug, $tag, &format!($($arg)*))
117    };
118    ($tag:expr) => {
119        $crate::log::log($crate::log::LogLevel::Debug, $tag, "")
120    };
121}
122
123#[macro_export]
124macro_rules! alog_info {
125    ($tag:expr, $($arg:tt)*) => {
126        $crate::log::log($crate::log::LogLevel::Info, $tag, &format!($($arg)*))
127    };
128    ($tag:expr) => {
129        $crate::log::log($crate::log::LogLevel::Info, $tag, "")
130    };
131}
132
133#[macro_export]
134macro_rules! alog_warn {
135    ($tag:expr, $($arg:tt)*) => {
136        $crate::log::log($crate::log::LogLevel::Warn, $tag, &format!($($arg)*))
137    };
138    ($tag:expr) => {
139        $crate::log::log($crate::log::LogLevel::Warn, $tag, "")
140    };
141}
142
143#[macro_export]
144macro_rules! alog_error {
145    ($tag:expr, $($arg:tt)*) => {
146        $crate::log::log($crate::log::LogLevel::Error, $tag, &format!($($arg)*))
147    };
148    ($tag:expr) => {
149        $crate::log::log($crate::log::LogLevel::Error, $tag, "")
150    };
151}
152
153#[macro_export]
154macro_rules! alog_fatal {
155    ($tag:expr, $($arg:tt)*) => {
156        $crate::log::log($crate::log::LogLevel::Fatal, $tag, &format!($($arg)*))
157    };
158    ($tag:expr) => {
159        $crate::log::log($crate::log::LogLevel::Fatal, $tag, "")
160    };
161}
162
163#[macro_export]
164macro_rules! log_verbose {
165    ($tag:expr, $($arg:tt)*) => {
166        $crate::log::log($crate::log::LogLevel::Verbose, $tag, &format!($($arg)*))
167    };
168    ($tag:expr) => {
169        $crate::log::log($crate::log::LogLevel::Verbose, $tag, "")
170    };
171}
172
173#[macro_export]
174macro_rules! log_debug {
175    ($tag:expr, $($arg:tt)*) => {
176        $crate::log::log($crate::log::LogLevel::Debug, $tag, &format!($($arg)*))
177    };
178    ($tag:expr) => {
179        $crate::log::log($crate::log::LogLevel::Debug, $tag, "")
180    };
181}
182
183#[macro_export]
184macro_rules! log_info {
185    ($tag:expr, $($arg:tt)*) => {
186        $crate::log::log($crate::log::LogLevel::Info, $tag, &format!($($arg)*))
187    };
188    ($tag:expr) => {
189        $crate::log::log($crate::log::LogLevel::Info, $tag, "")
190    };
191}
192
193#[macro_export]
194macro_rules! log_warn {
195    ($tag:expr, $($arg:tt)*) => {
196        $crate::log::log($crate::log::LogLevel::Warn, $tag, &format!($($arg)*))
197    };
198    ($tag:expr) => {
199        $crate::log::log($crate::log::LogLevel::Warn, $tag, "")
200    };
201}
202
203#[macro_export]
204macro_rules! log_error {
205    ($tag:expr, $($arg:tt)*) => {
206        $crate::log::log($crate::log::LogLevel::Error, $tag, &format!($($arg)*))
207    };
208    ($tag:expr) => {
209        $crate::log::log($crate::log::LogLevel::Error, $tag, "")
210    };
211}
212
213#[macro_export]
214macro_rules! log_fatal {
215    ($tag:expr, $($arg:tt)*) => {
216        $crate::log::log($crate::log::LogLevel::Fatal, $tag, &format!($($arg)*))
217    };
218    ($tag:expr) => {
219        $crate::log::log($crate::log::LogLevel::Fatal, $tag, "")
220    };
221}