| From a41a079a81f381f2002917fb1c030690e0798f0c Mon Sep 17 00:00:00 2001 |
| From: Jeff Vander Stoep <jeffv@google.com> |
| Date: Thu, 2 Feb 2023 13:33:47 +0100 |
| Subject: [PATCH] Support selecting target log buffer |
| |
| Android has several different log buffers. Previously, this library |
| would only support logging to the "Main" log. Now, it logs to the |
| default log (which is Main for most processes), with the option to |
| override which log buffer you send messages to in the config. |
| |
| Test: atest |
| Change-Id: I3cc393b989b8189675581ba6bf700f95715aa9e9 |
| --- |
| src/lib.rs | 73 +++++++++++++++++++++++++++++++++++++++++++----------- |
| 1 file changed, 59 insertions(+), 14 deletions(-) |
| |
| diff --git a/src/lib.rs b/src/lib.rs |
| index 0446fad..9ec7f0d 100644 |
| --- a/src/lib.rs |
| +++ b/src/lib.rs |
| @@ -85,21 +85,49 @@ pub use env_logger::fmt::Formatter; |
| |
| pub(crate) type FormatFn = Box<dyn Fn(&mut dyn fmt::Write, &Record) -> fmt::Result + Sync + Send>; |
| |
| +#[derive(Copy, Clone, Eq, PartialEq, Debug)] |
| +pub enum LogId { |
| + Main, |
| + Radio, |
| + Events, |
| + System, |
| + Crash |
| +} |
| + |
| +impl LogId { |
| + #[cfg(target_os = "android")] |
| + fn to_native(log_id: Option<Self>) -> log_ffi::log_id_t { |
| + match log_id { |
| + Some(LogId::Main) => log_ffi::log_id_t::MAIN, |
| + Some(LogId::Radio) => log_ffi::log_id_t::RADIO, |
| + Some(LogId::Events) => log_ffi::log_id_t::EVENTS, |
| + Some(LogId::System) => log_ffi::log_id_t::SYSTEM, |
| + Some(LogId::Crash) => log_ffi::log_id_t::CRASH, |
| + None => log_ffi::log_id_t::DEFAULT, |
| + } |
| + } |
| +} |
| + |
| /// Output log to android system. |
| #[cfg(target_os = "android")] |
| -fn android_log(prio: log_ffi::LogPriority, tag: &CStr, msg: &CStr) { |
| +fn android_log(log_id: log_ffi::log_id_t, prio: log_ffi::LogPriority, tag: &CStr, msg: &CStr) { |
| + let mut message = log_ffi::__android_log_message { |
| + struct_size: std::mem::size_of::<log_ffi::__android_log_message>(), |
| + buffer_id: log_id as i32, |
| + priority: prio as i32, |
| + tag: tag.as_ptr() as *const log_ffi::c_char, |
| + file: ptr::null(), |
| + line: 0, |
| + message: msg.as_ptr() as *const log_ffi::c_char, |
| + }; |
| unsafe { |
| - log_ffi::__android_log_write( |
| - prio as log_ffi::c_int, |
| - tag.as_ptr() as *const log_ffi::c_char, |
| - msg.as_ptr() as *const log_ffi::c_char, |
| - ) |
| + log_ffi::__android_log_write_log_message(&mut message as *mut _); |
| }; |
| } |
| |
| /// Dummy output placeholder for tests. |
| #[cfg(not(target_os = "android"))] |
| -fn android_log(_priority: Level, _tag: &CStr, _msg: &CStr) {} |
| +fn android_log(_log_id: Option<LogId>, _priority: Level, _tag: &CStr, _msg: &CStr) {} |
| |
| /// Underlying android logger backend |
| pub struct AndroidLogger { |
| @@ -172,7 +200,7 @@ impl Log for AndroidLogger { |
| |
| // message must not exceed LOGGING_MSG_MAX_LEN |
| // therefore split log message into multiple log calls |
| - let mut writer = PlatformLogWriter::new(record.level(), tag); |
| + let mut writer = PlatformLogWriter::new(config.log_id, record.level(), tag); |
| |
| // If a custom tag is used, add the module path to the message. |
| // Use PlatformLogWriter to output chunks if they exceed max size. |
| @@ -215,6 +243,7 @@ impl AndroidLogger { |
| #[derive(Default)] |
| pub struct Config { |
| log_level: Option<LevelFilter>, |
| + log_id: Option<LogId>, |
| filter: Option<env_logger::filter::Filter>, |
| tag: Option<CString>, |
| custom_format: Option<FormatFn>, |
| @@ -241,6 +270,15 @@ impl Config { |
| self |
| } |
| |
| + /// Change which log buffer is used |
| + /// |
| + /// By default, logs are sent to the `Main` log. Other logging buffers may only be accessible |
| + /// to certain processes. |
| + pub fn with_log_id(mut self, log_id: LogId) -> Self { |
| + self.log_id = Some(log_id); |
| + self |
| + } |
| + |
| fn filter_matches(&self, record: &Record) -> bool { |
| if let Some(ref filter) = self.filter { |
| filter.matches(record) |
| @@ -282,6 +320,8 @@ pub struct PlatformLogWriter<'a> { |
| priority: LogPriority, |
| #[cfg(not(target_os = "android"))] |
| priority: Level, |
| + #[cfg(target_os = "android")] log_id: log_ffi::log_id_t, |
| + #[cfg(not(target_os = "android"))] log_id: Option<LogId>, |
| len: usize, |
| last_newline_index: usize, |
| tag: &'a CStr, |
| @@ -290,10 +330,11 @@ pub struct PlatformLogWriter<'a> { |
| |
| impl<'a> PlatformLogWriter<'a> { |
| #[cfg(target_os = "android")] |
| - pub fn new_with_priority(priority: log_ffi::LogPriority, tag: &CStr) -> PlatformLogWriter { |
| + pub fn new_with_priority(log_id: Option<LogId>, priority: log_ffi::LogPriority, tag: &CStr) -> PlatformLogWriter { |
| #[allow(deprecated)] // created an issue #35 for this |
| PlatformLogWriter { |
| priority, |
| + log_id: LogId::to_native(log_id), |
| len: 0, |
| last_newline_index: 0, |
| tag, |
| @@ -302,8 +343,9 @@ impl<'a> PlatformLogWriter<'a> { |
| } |
| |
| #[cfg(target_os = "android")] |
| - pub fn new(level: Level, tag: &CStr) -> PlatformLogWriter { |
| + pub fn new(log_id: Option<LogId>, level: Level, tag: &CStr) -> PlatformLogWriter { |
| Self::new_with_priority( |
| + log_id, |
| match level { |
| Level::Warn => LogPriority::WARN, |
| Level::Info => LogPriority::INFO, |
| @@ -316,10 +358,11 @@ impl<'a> PlatformLogWriter<'a> { |
| } |
| |
| #[cfg(not(target_os = "android"))] |
| - pub fn new(level: Level, tag: &CStr) -> PlatformLogWriter { |
| + pub fn new(log_id: Option<LogId>, level: Level, tag: &CStr) -> PlatformLogWriter { |
| #[allow(deprecated)] // created an issue #35 for this |
| PlatformLogWriter { |
| priority: level, |
| + log_id, |
| len: 0, |
| last_newline_index: 0, |
| tag, |
| @@ -376,7 +419,7 @@ impl<'a> PlatformLogWriter<'a> { |
| }); |
| |
| let msg: &CStr = unsafe { CStr::from_ptr(self.buffer.as_ptr().cast()) }; |
| - android_log(self.priority, self.tag, msg); |
| + android_log(self.log_id, self.priority, self.tag, msg); |
| |
| unsafe { *self.buffer.get_unchecked_mut(len) = last_byte }; |
| } |
| @@ -481,9 +524,11 @@ mod tests { |
| // Filter is checked in config_filter_match below. |
| let config = Config::default() |
| .with_max_level(LevelFilter::Trace) |
| + .with_log_id(LogId::System) |
| .with_tag("my_app"); |
| |
| assert_eq!(config.log_level, Some(LevelFilter::Trace)); |
| + assert_eq!(config.log_id, Some(LogId::System)); |
| assert_eq!(config.tag, Some(CString::new("my_app").unwrap())); |
| } |
| |
| @@ -556,7 +601,7 @@ mod tests { |
| fn platform_log_writer_init_values() { |
| let tag = CStr::from_bytes_with_nul(b"tag\0").unwrap(); |
| |
| - let writer = PlatformLogWriter::new(Level::Warn, tag); |
| + let writer = PlatformLogWriter::new(None, Level::Warn, tag); |
| |
| assert_eq!(writer.tag, tag); |
| // Android uses LogPriority instead, which doesn't implement equality checks |
| @@ -661,7 +706,7 @@ mod tests { |
| } |
| |
| fn get_tag_writer() -> PlatformLogWriter<'static> { |
| - PlatformLogWriter::new(Level::Warn, CStr::from_bytes_with_nul(b"tag\0").unwrap()) |
| + PlatformLogWriter::new(None, Level::Warn, CStr::from_bytes_with_nul(b"tag\0").unwrap()) |
| } |
| |
| unsafe fn assume_init_slice<T>(slice: &[MaybeUninit<T>]) -> &[T] { |
| -- |
| 2.39.1.456.gfc5497dd1b-goog |
| |