1From 2bc2650d0a7a11a74670a6583b16aa6714d7c993 Mon Sep 17 00:00:00 2001 2From: Matthew Maurer <mmaurer@google.com> 3Date: Thu, 17 Feb 2022 20:23:37 +0000 4Subject: [PATCH] Support selecting target log buffer 5 6Android has several different log buffers. Previously, this library 7would only support logging to the "Main" log. Now, it logs to the 8default log (which is Main for most processes), with the option to 9override which log buffer you send messages to in the config. 10 11Change-Id: I72779e62bd963586e3dfad431cd82c75daf04d92 12--- 13 src/lib.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++---------- 14 1 file changed, 58 insertions(+), 13 deletions(-) 15 16diff --git a/src/lib.rs b/src/lib.rs 17index 11a127e..d21be3f 100644 18--- a/src/lib.rs 19+++ b/src/lib.rs 20@@ -87,21 +87,49 @@ pub use env_logger::fmt::Formatter; 21 22 pub(crate) type FormatFn = Box<dyn Fn(&mut dyn fmt::Write, &Record) -> fmt::Result + Sync + Send>; 23 24+#[derive(Copy, Clone, Eq, PartialEq, Debug)] 25+pub enum LogId { 26+ Main, 27+ Radio, 28+ Events, 29+ System, 30+ Crash 31+} 32+ 33+impl LogId { 34+ #[cfg(target_os = "android")] 35+ fn to_native(log_id: Option<Self>) -> log_ffi::log_id_t { 36+ match log_id { 37+ Some(LogId::Main) => log_ffi::log_id_t::MAIN, 38+ Some(LogId::Radio) => log_ffi::log_id_t::RADIO, 39+ Some(LogId::Events) => log_ffi::log_id_t::EVENTS, 40+ Some(LogId::System) => log_ffi::log_id_t::SYSTEM, 41+ Some(LogId::Crash) => log_ffi::log_id_t::CRASH, 42+ None => log_ffi::log_id_t::DEFAULT, 43+ } 44+ } 45+} 46+ 47 /// Output log to android system. 48 #[cfg(target_os = "android")] 49-fn android_log(prio: log_ffi::LogPriority, tag: &CStr, msg: &CStr) { 50+fn android_log(log_id: log_ffi::log_id_t, prio: log_ffi::LogPriority, tag: &CStr, msg: &CStr) { 51+ let mut message = log_ffi::__android_log_message { 52+ struct_size: std::mem::size_of::<log_ffi::__android_log_message>(), 53+ buffer_id: log_id as i32, 54+ priority: prio as i32, 55+ tag: tag.as_ptr() as *const log_ffi::c_char, 56+ file: ptr::null(), 57+ line: 0, 58+ message: msg.as_ptr() as *const log_ffi::c_char, 59+ }; 60 unsafe { 61- log_ffi::__android_log_write( 62- prio as log_ffi::c_int, 63- tag.as_ptr() as *const log_ffi::c_char, 64- msg.as_ptr() as *const log_ffi::c_char, 65- ) 66+ log_ffi::__android_log_write_log_message(&mut message as *mut _); 67 }; 68 } 69 70 /// Dummy output placeholder for tests. 71 #[cfg(not(target_os = "android"))] 72-fn android_log(_priority: Level, _tag: &CStr, _msg: &CStr) {} 73+fn android_log(_log_id: Option<LogId>, _priority: Level, _tag: &CStr, _msg: &CStr) {} 74 75 /// Underlying android logger backend 76 pub struct AndroidLogger { 77@@ -164,7 +192,7 @@ impl Log for AndroidLogger { 78 79 // message must not exceed LOGGING_MSG_MAX_LEN 80 // therefore split log message into multiple log calls 81- let mut writer = PlatformLogWriter::new(record.level(), tag); 82+ let mut writer = PlatformLogWriter::new(config.log_id, record.level(), tag); 83 84 // If a custom tag is used, add the module path to the message. 85 // Use PlatformLogWriter to output chunks if they exceed max size. 86@@ -208,6 +236,7 @@ impl AndroidLogger { 87 /// Filter for android logger. 88 pub struct Config { 89 log_level: Option<Level>, 90+ log_id: Option<LogId>, 91 filter: Option<env_logger::filter::Filter>, 92 tag: Option<CString>, 93 custom_format: Option<FormatFn>, 94@@ -217,6 +246,7 @@ impl Default for Config { 95 fn default() -> Self { 96 Config { 97 log_level: None, 98+ log_id: None, 99 filter: None, 100 tag: None, 101 custom_format: None, 102@@ -234,6 +264,15 @@ impl Config { 103 self 104 } 105 106+ /// Change which log buffer is used 107+ /// 108+ /// By default, logs are sent to the `Main` log. Other logging buffers may only be accessible 109+ /// to certain processes. 110+ pub fn with_log_id(mut self, log_id: LogId) -> Self { 111+ self.log_id = Some(log_id); 112+ self 113+ } 114+ 115 fn filter_matches(&self, record: &Record) -> bool { 116 if let Some(ref filter) = self.filter { 117 filter.matches(&record) 118@@ -273,6 +312,8 @@ impl Config { 119 struct PlatformLogWriter<'a> { 120 #[cfg(target_os = "android")] priority: LogPriority, 121 #[cfg(not(target_os = "android"))] priority: Level, 122+ #[cfg(target_os = "android")] log_id: log_ffi::log_id_t, 123+ #[cfg(not(target_os = "android"))] log_id: Option<LogId>, 124 len: usize, 125 last_newline_index: usize, 126 tag: &'a CStr, 127@@ -281,7 +322,7 @@ struct PlatformLogWriter<'a> { 128 129 impl<'a> PlatformLogWriter<'a> { 130 #[cfg(target_os = "android")] 131- pub fn new(level: Level, tag: &CStr) -> PlatformLogWriter { 132+ pub fn new(log_id: Option<LogId>, level: Level, tag: &CStr) -> PlatformLogWriter { 133 #[allow(deprecated)] // created an issue #35 for this 134 PlatformLogWriter { 135 priority: match level { 136@@ -291,6 +332,7 @@ impl<'a> PlatformLogWriter<'a> { 137 Level::Error => LogPriority::ERROR, 138 Level::Trace => LogPriority::VERBOSE, 139 }, 140+ log_id: LogId::to_native(log_id), 141 len: 0, 142 last_newline_index: 0, 143 tag, 144@@ -299,10 +341,11 @@ impl<'a> PlatformLogWriter<'a> { 145 } 146 147 #[cfg(not(target_os = "android"))] 148- pub fn new(level: Level, tag: &CStr) -> PlatformLogWriter { 149+ pub fn new(log_id: Option<LogId>, level: Level, tag: &CStr) -> PlatformLogWriter { 150 #[allow(deprecated)] // created an issue #35 for this 151 PlatformLogWriter { 152 priority: level, 153+ log_id, 154 len: 0, 155 last_newline_index: 0, 156 tag, 157@@ -358,7 +401,7 @@ impl<'a> PlatformLogWriter<'a> { 158 }); 159 160 let msg: &CStr = unsafe { CStr::from_ptr(mem::transmute(self.buffer.as_ptr())) }; 161- android_log(self.priority, self.tag, msg); 162+ android_log(self.log_id, self.priority, self.tag, msg); 163 164 *unsafe { self.buffer.get_unchecked_mut(len) } = last_byte; 165 } 166@@ -458,9 +501,11 @@ mod tests { 167 // Filter is checked in config_filter_match below. 168 let config = Config::default() 169 .with_min_level(Level::Trace) 170+ .with_log_id(LogId::System) 171 .with_tag("my_app"); 172 173 assert_eq!(config.log_level, Some(Level::Trace)); 174+ assert_eq!(config.log_id, Some(LogId::System)); 175 assert_eq!(config.tag, Some(CString::new("my_app").unwrap())); 176 } 177 178@@ -531,7 +576,7 @@ mod tests { 179 fn platform_log_writer_init_values() { 180 let tag = CStr::from_bytes_with_nul(b"tag\0").unwrap(); 181 182- let writer = PlatformLogWriter::new(Level::Warn, &tag); 183+ let writer = PlatformLogWriter::new(None, Level::Warn, &tag); 184 185 assert_eq!(writer.tag, tag); 186 // Android uses LogPriority instead, which doesn't implement equality checks 187@@ -630,6 +675,6 @@ mod tests { 188 } 189 190 fn get_tag_writer() -> PlatformLogWriter<'static> { 191- PlatformLogWriter::new(Level::Warn, &CStr::from_bytes_with_nul(b"tag\0").unwrap()) 192+ PlatformLogWriter::new(None, Level::Warn, &CStr::from_bytes_with_nul(b"tag\0").unwrap()) 193 } 194 } 195-- 1962.35.1.265.g69c8d7142f-goog 197 198