| From 1eeada2dcbf268c7beaad0f48c6ca0664c646fde Mon Sep 17 00:00:00 2001 |
| From: Jeff Vander Stoep <jeffv@google.com> |
| Date: Mon, 23 Jan 2023 07:55:16 +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: I021158b302796cf7249177f60c8c984c988cb61c |
| --- |
| src/lib.rs | 73 +++++++++++++++++++++++++++++++++++++++++++----------- |
| 1 file changed, 59 insertions(+), 14 deletions(-) |
| |
| diff --git a/src/lib.rs b/src/lib.rs |
| index d443c91..193bd29 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<Level>, |
| + log_id: Option<LogId>, |
| filter: Option<env_logger::filter::Filter>, |
| tag: Option<CString>, |
| custom_format: Option<FormatFn>, |
| @@ -230,6 +259,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) |
| @@ -271,6 +309,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, |
| @@ -279,10 +319,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, |
| @@ -291,8 +332,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, |
| @@ -305,10 +347,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, |
| @@ -365,7 +408,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 }; |
| } |
| @@ -470,9 +513,11 @@ mod tests { |
| // Filter is checked in config_filter_match below. |
| let config = Config::default() |
| .with_min_level(Level::Trace) |
| + .with_log_id(LogId::System) |
| .with_tag("my_app"); |
| |
| assert_eq!(config.log_level, Some(Level::Trace)); |
| + assert_eq!(config.log_id, Some(LogId::System)); |
| assert_eq!(config.tag, Some(CString::new("my_app").unwrap())); |
| } |
| |
| @@ -543,7 +588,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 |
| @@ -648,7 +693,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.0.246.g2a6d74b583-goog |
| |