Skip to content

Commit

Permalink
Support selecting target buffer of Android logging system (#50, #64)
Browse files Browse the repository at this point in the history
- add `LogId` enum to identify the different log buffers
- add `buf_id` argument to `PlatformLogWriter::new()`
- add `Config::with_log_buffer()` allowing to specify target buffer

Co-authored-by: David LeGare <[email protected]>
Co-authored-by: Kai Ren <[email protected]>
  • Loading branch information
3 people authored Feb 14, 2023
1 parent 9398978 commit fee1bea
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 14 deletions.
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,25 @@ All user visible changes to this project will be documented in this file. This p



## [0.13.0] · 2023-02-??
[0.13.0]: /../../tree/v0.13.0

[Diff](/../../compare/v0.12.0...v0.13.0)

### BC Breaks

- Added `buf_id` argument to `PlatformLogWriter::new()` method allowing to specify concrete Android logging system buffer. ([#50], [#64])

### Added

- `Config::with_log_buffer()` method to specify concrete Android logging system buffer. ([#50], [#64])

[#50]: /../../pull/50
[#64]: /../../pull/64




## [0.12.0] · 2023-01-19
[0.12.0]: /../../tree/v0.12.0

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ once_cell = "1.9"
version = "0.4"

[dependencies.android_log-sys]
version = "0.2"
version = "0.3"

[dependencies.env_logger]
version = "0.10"
Expand Down
104 changes: 91 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,21 +85,70 @@ pub use env_logger::fmt::Formatter;

pub(crate) type FormatFn = Box<dyn Fn(&mut dyn fmt::Write, &Record) -> fmt::Result + Sync + Send>;

/// Output log to android system.
/// Possible identifiers of a specific buffer of Android logging system for
/// logging a message.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LogId {
/// Main log buffer.
///
/// This is the only log buffer available to apps.
Main,

/// Radio log buffer.
Radio,

/// Event log buffer.
Events,

/// System log buffer.
System,

/// Crash log buffer.
Crash,

/// Kernel log buffer.
Kernel,

/// Security log buffer.
Security,

/// Statistics log buffer.
Stats,
}

#[cfg(target_os = "android")]
fn android_log(prio: log_ffi::LogPriority, tag: &CStr, msg: &CStr) {
impl LogId {
fn to_native(log_id: Option<Self>) -> log_ffi::log_id_t {
match log_id {
Some(Self::Main) => log_ffi::log_id_t::MAIN,
Some(Self::Radio) => log_ffi::log_id_t::RADIO,
Some(Self::Events) => log_ffi::log_id_t::EVENTS,
Some(Self::System) => log_ffi::log_id_t::SYSTEM,
Some(Self::Crash) => log_ffi::log_id_t::CRASH,
Some(Self::Kernel) => log_ffi::log_id_t::KERNEL,
Some(Self::Security) => log_ffi::log_id_t::SECURITY,
Some(Self::Stats) => log_ffi::log_id_t::STATS,
None => log_ffi::log_id_t::DEFAULT,
}
}
}

/// Outputs log to Android system.
#[cfg(target_os = "android")]
fn android_log(buf_id: log_ffi::log_id_t, prio: log_ffi::LogPriority, tag: &CStr, msg: &CStr) {
unsafe {
log_ffi::__android_log_write(
log_ffi::__android_log_buf_write(
buf_id as log_ffi::c_int,
prio as log_ffi::c_int,
tag.as_ptr() as *const log_ffi::c_char,
msg.as_ptr() as *const log_ffi::c_char,
)
);
};
}

/// Dummy output placeholder for tests.
#[cfg(not(target_os = "android"))]
fn android_log(_priority: Level, _tag: &CStr, _msg: &CStr) {}
fn android_log(_buf_id: Option<LogId>, _priority: Level, _tag: &CStr, _msg: &CStr) {}

/// Underlying android logger backend
pub struct AndroidLogger {
Expand Down Expand Up @@ -172,7 +221,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.buf_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.
Expand Down Expand Up @@ -215,6 +264,7 @@ impl AndroidLogger {
#[derive(Default)]
pub struct Config {
log_level: Option<LevelFilter>,
buf_id: Option<LogId>,
filter: Option<env_logger::filter::Filter>,
tag: Option<CString>,
custom_format: Option<FormatFn>,
Expand All @@ -241,6 +291,17 @@ impl Config {
self
}

/// Changes the Android logging system buffer to be used.
///
/// By default, logs are sent to the [`Main`] log. Other logging buffers may
/// only be accessible to certain processes.
///
/// [`Main`]: LogId::Main
pub fn with_log_buffer(mut self, buf_id: LogId) -> Self {
self.buf_id = Some(buf_id);
self
}

fn filter_matches(&self, record: &Record) -> bool {
if let Some(ref filter) = self.filter {
filter.matches(record)
Expand Down Expand Up @@ -282,6 +343,10 @@ pub struct PlatformLogWriter<'a> {
priority: LogPriority,
#[cfg(not(target_os = "android"))]
priority: Level,
#[cfg(target_os = "android")]
buf_id: log_ffi::log_id_t,
#[cfg(not(target_os = "android"))]
buf_id: Option<LogId>,
len: usize,
last_newline_index: usize,
tag: &'a CStr,
Expand All @@ -290,10 +355,15 @@ 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(
buf_id: Option<LogId>,
priority: log_ffi::LogPriority,
tag: &CStr,
) -> PlatformLogWriter<'_> {
#[allow(deprecated)] // created an issue #35 for this
PlatformLogWriter {
priority,
buf_id: LogId::to_native(buf_id),
len: 0,
last_newline_index: 0,
tag,
Expand All @@ -302,8 +372,9 @@ impl<'a> PlatformLogWriter<'a> {
}

#[cfg(target_os = "android")]
pub fn new(level: Level, tag: &CStr) -> PlatformLogWriter {
Self::new_with_priority(
pub fn new(buf_id: Option<LogId>, level: Level, tag: &CStr) -> PlatformLogWriter<'_> {
PlatformLogWriter::new_with_priority(
buf_id,
match level {
Level::Warn => LogPriority::WARN,
Level::Info => LogPriority::INFO,
Expand All @@ -316,10 +387,11 @@ impl<'a> PlatformLogWriter<'a> {
}

#[cfg(not(target_os = "android"))]
pub fn new(level: Level, tag: &CStr) -> PlatformLogWriter {
pub fn new(buf_id: Option<LogId>, level: Level, tag: &CStr) -> PlatformLogWriter<'_> {
#[allow(deprecated)] // created an issue #35 for this
PlatformLogWriter {
priority: level,
buf_id,
len: 0,
last_newline_index: 0,
tag,
Expand Down Expand Up @@ -376,7 +448,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.buf_id, self.priority, self.tag, msg);

unsafe { *self.buffer.get_unchecked_mut(len) = last_byte };
}
Expand Down Expand Up @@ -481,9 +553,11 @@ mod tests {
// Filter is checked in config_filter_match below.
let config = Config::default()
.with_max_level(LevelFilter::Trace)
.with_log_buffer(LogId::System)
.with_tag("my_app");

assert_eq!(config.log_level, Some(LevelFilter::Trace));
assert_eq!(config.buf_id, Some(LogId::System));
assert_eq!(config.tag, Some(CString::new("my_app").unwrap()));
}

Expand Down Expand Up @@ -556,7 +630,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
Expand Down Expand Up @@ -661,7 +735,11 @@ 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] {
Expand Down

0 comments on commit fee1bea

Please sign in to comment.