diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-07-07 05:04:28 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-07-07 05:04:28 +0000 |
commit | 907aca63a329a52b0c69342269b9f37ce2c5ea65 (patch) | |
tree | c947a8493fdab7473512377a3213273b45430dc7 | |
parent | f9f6753386f741dd38fa05ab3c5e072ef542715c (diff) | |
parent | f6151f845dd997a9e324388d07b7142c6c346914 (diff) | |
download | android_logger-907aca63a329a52b0c69342269b9f37ce2c5ea65.tar.gz |
Snap for 10453563 from f6151f845dd997a9e324388d07b7142c6c346914 to mainline-os-statsd-releaseaml_sta_341710000aml_sta_341615000aml_sta_341511040aml_sta_341410000aml_sta_341311010aml_sta_341114000aml_sta_341111000aml_sta_341010020aml_sta_340912000aml_sta_340911000aml_net_341111030android14-mainline-os-statsd-release
Change-Id: I3c23e98ae6e03a003b96fa2ddf0e754e96deb2dc
-rw-r--r-- | .cargo_vcs_info.json | 7 | ||||
-rw-r--r-- | Android.bp | 19 | ||||
-rw-r--r-- | CHANGELOG.md | 54 | ||||
-rw-r--r-- | Cargo.toml | 32 | ||||
-rw-r--r-- | Cargo.toml.orig | 6 | ||||
-rw-r--r-- | METADATA | 13 | ||||
-rw-r--r-- | OWNERS | 2 | ||||
-rw-r--r-- | README.md | 11 | ||||
-rw-r--r-- | TEST_MAPPING | 73 | ||||
-rw-r--r-- | cargo2android.json | 6 | ||||
-rw-r--r-- | patches/0001-Support-selecting-target-log-buffer.patch | 99 | ||||
-rw-r--r-- | patches/0002-Use-older-API-to-avoid-requiring-API-v30.patch | 16 | ||||
-rw-r--r-- | src/lib.rs | 227 | ||||
-rw-r--r-- | tests/config_log_level.rs | 6 | ||||
-rw-r--r-- | tests/default_init.rs | 2 | ||||
-rw-r--r-- | tests/multiple_init.rs | 10 |
16 files changed, 320 insertions, 263 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 00435b7..c1be5ef 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,6 @@ { "git": { - "sha1": "c20ec25acacf0731583140b230e6ce94e59b054d" - } -} + "sha1": "596b92d5907f0054884412d2f7137704edae4208" + }, + "path_in_vcs": "" +}
\ No newline at end of file @@ -43,7 +43,7 @@ rust_test { name: "android_logger_test_src_lib", crate_name: "android_logger", cargo_env_compat: true, - cargo_pkg_version: "0.10.1", + cargo_pkg_version: "0.12.0", srcs: ["src/lib.rs"], test_suites: ["general-tests"], auto_gen_config: true, @@ -55,8 +55,8 @@ rust_test { rustlibs: [ "libandroid_log_sys", "libenv_logger", - "liblazy_static", "liblog_rust", + "libonce_cell", ], } @@ -64,7 +64,7 @@ rust_defaults { name: "android_logger_test_defaults", crate_name: "android_logger", cargo_env_compat: true, - cargo_pkg_version: "0.10.1", + cargo_pkg_version: "0.12.0", test_suites: ["general-tests"], auto_gen_config: true, edition: "2015", @@ -76,8 +76,8 @@ rust_defaults { "libandroid_log_sys", "libandroid_logger", "libenv_logger", - "liblazy_static", "liblog_rust", + "libonce_cell", ], } @@ -103,7 +103,7 @@ rust_library { name: "libandroid_logger", crate_name: "android_logger", cargo_env_compat: true, - cargo_pkg_version: "0.10.1", + cargo_pkg_version: "0.12.0", srcs: ["src/lib.rs"], edition: "2015", features: [ @@ -113,17 +113,14 @@ rust_library { rustlibs: [ "libandroid_log_sys", "libenv_logger", - "liblazy_static", "liblog_rust", + "libonce_cell", ], apex_available: [ "//apex_available:platform", - "com.android.bluetooth", - "com.android.compos", - "com.android.resolv", - "com.android.uwb", - "com.android.virt", + "//apex_available:anyapex", ], + product_available: true, vendor_available: true, min_sdk_version: "29", } diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..4952ca1 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,54 @@ +`android_logger` changelog +========================== + +All user visible changes to this project will be documented in this file. This project uses [Semantic Versioning 2.0.0]. + + + + +## [0.12.0] · 2023-01-19 +[0.12.0]: /../../tree/v0.12.0 + +[Diff](/../../compare/v0.11.3...v0.12.0) + +### Added + +- `Config::with_max_level()` method to filters logs via `log::LevelFilter`. ([#62]) + +### Deprecated + +- `Config::with_min_level()` method accepting `log::Level`. ([#62]) + +### Fixed + +- Incorrect logs level filtering. ([#62]) + +[#62]: /../../pull/62 + + + + +## [0.11.3] · 2022-12-20 +[0.11.3]: /../../tree/v0.11.3 + +[Diff](/../../compare/38186ece1056d90b8f75fd2a5eb5c860e0a1704e...v0.11.3) + +### Fixed + +- Broken compilation on [Android] targets. ([#59], [#58]) + +[#58]: /../../issues/58 +[#59]: /../../pull/59 + + + + +## Previous releases + +See [Git log](/../../commits/master?after=1a5a07ec6742f0069acc2be223c1bb3b6a9d15f8+0). + + + + +[Android]: https://www.android.com +[Semantic Versioning 2.0.0]: https://semver.org @@ -3,38 +3,46 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] name = "android_logger" -version = "0.10.1" +version = "0.12.0" authors = ["The android_logger Developers"] -description = "A logging implementation for `log` which hooks to android log output.\n" +description = """ +A logging implementation for `log` which hooks to android log output. +""" readme = "README.md" -keywords = ["android", "bindings", "log", "logger"] +keywords = [ + "android", + "bindings", + "log", + "logger", +] categories = ["api-bindings"] license = "MIT OR Apache-2.0" repository = "https://github.com/Nercury/android_logger-rs" + [dependencies.android_log-sys] version = "0.2" [dependencies.env_logger] -version = "0.8" +version = "0.10" default-features = false -[dependencies.lazy_static] -version = "1.4" - [dependencies.log] version = "0.4" +[dependencies.once_cell] +version = "1.9" + [features] default = ["regex"] regex = ["env_logger/regex"] + [badges.travis-ci] repository = "Nercury/android_logger-rs" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index a9ad77f..ca1b723 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "android_logger" -version = "0.10.1" +version = "0.12.0" authors = ["The android_logger Developers"] license = "MIT OR Apache-2.0" readme = "README.md" @@ -16,7 +16,7 @@ default = ["regex"] regex = ["env_logger/regex"] [dependencies] -lazy_static = "1.4" +once_cell = "1.9" [dependencies.log] version = "0.4" @@ -25,7 +25,7 @@ version = "0.4" version = "0.2" [dependencies.env_logger] -version = "0.8" +version = "0.10" default-features = false [badges] @@ -1,5 +1,5 @@ name: "android_logger" -description: "A logging implementation for `log` which hooks to android log output." +description: "()" third_party { url { type: HOMEPAGE @@ -7,13 +7,14 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/android_logger/android_logger-0.10.1.crate" + value: "https://static.crates.io/crates/android_logger/android_logger-0.12.0.crate" } - version: "0.10.1" + version: "0.12.0" + # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same. license_type: NOTICE last_upgrade_date { - year: 2021 - month: 4 - day: 19 + year: 2023 + month: 2 + day: 2 } } @@ -1 +1 @@ -include platform/prebuilts/rust:/OWNERS +include platform/prebuilts/rust:master:/OWNERS @@ -13,7 +13,7 @@ this library: ```toml [target.'cfg(target_os = "android")'.dependencies] -android_logger = "0.10" +android_logger = "0.11" ``` Example of initialization on activity creation, with log configuration: @@ -22,13 +22,13 @@ Example of initialization on activity creation, with log configuration: #[macro_use] extern crate log; extern crate android_logger; -use log::Level; +use log::LevelFilter; use android_logger::{Config,FilterBuilder}; fn native_activity_create() { android_logger::init_once( Config::default() - .with_min_level(Level::Trace) // limit log level + .with_max_level(LevelFilter::Trace) // limit log level .with_tag("mytag") // logs will show under mytag tag .with_filter( // configure messages for specific crate FilterBuilder::new() @@ -47,12 +47,13 @@ To allow all logs, use the default configuration with min level Trace: #[macro_use] extern crate log; extern crate android_logger; -use log::Level; +use log::LevelFilter; use android_logger::Config; fn native_activity_create() { android_logger::init_once( - Config::default().with_min_level(Level::Trace)); + Config::default().with_max_level(LevelFilter::Trace), + ); } ``` diff --git a/TEST_MAPPING b/TEST_MAPPING index 526e77a..d42c05d 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -1,50 +1,40 @@ // Generated by update_crate_tests.py for tests that depend on this crate. { - "presubmit": [ - { - "name": "android_logger_test_src_lib" - }, - { - "name": "android_logger_test_tests_config_log_level" - }, - { - "name": "android_logger_test_tests_default_init" - }, - { - "name": "android_logger_test_tests_multiple_init" - }, + "imports": [ { - "name": "authfs_device_test_src_lib" + "path": "packages/modules/DnsResolver" }, { - "name": "doh_unit_test" + "path": "packages/modules/Virtualization/authfs" }, { - "name": "keystore2_selinux_concurrency_test" + "path": "packages/modules/Virtualization/encryptedstore" }, { - "name": "keystore2_selinux_test" + "path": "packages/modules/Virtualization/virtualizationmanager" }, { - "name": "keystore2_test" + "path": "system/logging/rust" }, { - "name": "logger_device_unit_tests" + "path": "system/security/keystore2" }, { - "name": "logger_test_config_log_level" - }, + "path": "system/security/keystore2/selinux" + } + ], + "presubmit": [ { - "name": "logger_test_default_init" + "name": "android_logger_test_src_lib" }, { - "name": "logger_test_env_log_level" + "name": "android_logger_test_tests_config_log_level" }, { - "name": "logger_test_multiple_init" + "name": "android_logger_test_tests_default_init" }, { - "name": "virtualizationservice_device_test" + "name": "android_logger_test_tests_multiple_init" } ], "presubmit-rust": [ @@ -59,39 +49,6 @@ }, { "name": "android_logger_test_tests_multiple_init" - }, - { - "name": "authfs_device_test_src_lib" - }, - { - "name": "doh_unit_test" - }, - { - "name": "keystore2_selinux_concurrency_test" - }, - { - "name": "keystore2_selinux_test" - }, - { - "name": "keystore2_test" - }, - { - "name": "logger_device_unit_tests" - }, - { - "name": "logger_test_config_log_level" - }, - { - "name": "logger_test_default_init" - }, - { - "name": "logger_test_env_log_level" - }, - { - "name": "logger_test_multiple_init" - }, - { - "name": "virtualizationservice_device_test" } ] } diff --git a/cargo2android.json b/cargo2android.json index 18ba06d..2733be4 100644 --- a/cargo2android.json +++ b/cargo2android.json @@ -1,11 +1,7 @@ { "apex-available": [ "//apex_available:platform", - "com.android.bluetooth", - "com.android.compos", - "com.android.resolv", - "com.android.uwb", - "com.android.virt" + "//apex_available:anyapex" ], "dependencies": true, "device": true, diff --git a/patches/0001-Support-selecting-target-log-buffer.patch b/patches/0001-Support-selecting-target-log-buffer.patch index e5fc33b..a9e11a4 100644 --- a/patches/0001-Support-selecting-target-log-buffer.patch +++ b/patches/0001-Support-selecting-target-log-buffer.patch @@ -1,6 +1,6 @@ -From 2bc2650d0a7a11a74670a6583b16aa6714d7c993 Mon Sep 17 00:00:00 2001 -From: Matthew Maurer <mmaurer@google.com> -Date: Thu, 17 Feb 2022 20:23:37 +0000 +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 @@ -8,16 +8,17 @@ 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. -Change-Id: I72779e62bd963586e3dfad431cd82c75daf04d92 +Test: atest +Change-Id: I3cc393b989b8189675581ba6bf700f95715aa9e9 --- - src/lib.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++---------- - 1 file changed, 58 insertions(+), 13 deletions(-) + src/lib.rs | 73 +++++++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 59 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs -index 11a127e..d21be3f 100644 +index 0446fad..9ec7f0d 100644 --- a/src/lib.rs +++ b/src/lib.rs -@@ -87,21 +87,49 @@ pub use env_logger::fmt::Formatter; +@@ -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>; @@ -74,7 +75,7 @@ index 11a127e..d21be3f 100644 /// Underlying android logger backend pub struct AndroidLogger { -@@ -164,7 +192,7 @@ impl Log for 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 @@ -83,23 +84,15 @@ index 11a127e..d21be3f 100644 // If a custom tag is used, add the module path to the message. // Use PlatformLogWriter to output chunks if they exceed max size. -@@ -208,6 +236,7 @@ impl AndroidLogger { - /// Filter for android logger. +@@ -215,6 +243,7 @@ impl AndroidLogger { + #[derive(Default)] pub struct Config { - log_level: Option<Level>, + log_level: Option<LevelFilter>, + log_id: Option<LogId>, filter: Option<env_logger::filter::Filter>, tag: Option<CString>, custom_format: Option<FormatFn>, -@@ -217,6 +246,7 @@ impl Default for Config { - fn default() -> Self { - Config { - log_level: None, -+ log_id: None, - filter: None, - tag: None, - custom_format: None, -@@ -234,6 +264,15 @@ impl Config { +@@ -241,6 +270,15 @@ impl Config { self } @@ -114,34 +107,41 @@ index 11a127e..d21be3f 100644 + fn filter_matches(&self, record: &Record) -> bool { if let Some(ref filter) = self.filter { - filter.matches(&record) -@@ -273,6 +312,8 @@ impl Config { - struct PlatformLogWriter<'a> { - #[cfg(target_os = "android")] priority: LogPriority, - #[cfg(not(target_os = "android"))] priority: Level, + 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, -@@ -281,7 +322,7 @@ struct PlatformLogWriter<'a> { +@@ -290,10 +330,11 @@ pub struct PlatformLogWriter<'a> { 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 { +- 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: match level { -@@ -291,6 +332,7 @@ impl<'a> PlatformLogWriter<'a> { - Level::Error => LogPriority::ERROR, - Level::Trace => LogPriority::VERBOSE, - }, + priority, + log_id: LogId::to_native(log_id), len: 0, last_newline_index: 0, tag, -@@ -299,10 +341,11 @@ impl<'a> PlatformLogWriter<'a> { +@@ -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"))] @@ -154,44 +154,45 @@ index 11a127e..d21be3f 100644 len: 0, last_newline_index: 0, tag, -@@ -358,7 +401,7 @@ impl<'a> PlatformLogWriter<'a> { +@@ -376,7 +419,7 @@ impl<'a> PlatformLogWriter<'a> { }); - let msg: &CStr = unsafe { CStr::from_ptr(mem::transmute(self.buffer.as_ptr())) }; + 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; + unsafe { *self.buffer.get_unchecked_mut(len) = last_byte }; } -@@ -458,9 +501,11 @@ mod tests { +@@ -481,9 +524,11 @@ mod tests { // Filter is checked in config_filter_match below. let config = Config::default() - .with_min_level(Level::Trace) + .with_max_level(LevelFilter::Trace) + .with_log_id(LogId::System) .with_tag("my_app"); - assert_eq!(config.log_level, Some(Level::Trace)); + 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())); } -@@ -531,7 +576,7 @@ mod tests { +@@ -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); +- 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 -@@ -630,6 +675,6 @@ mod tests { +@@ -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()) +- 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.35.1.265.g69c8d7142f-goog +2.39.1.456.gfc5497dd1b-goog diff --git a/patches/0002-Use-older-API-to-avoid-requiring-API-v30.patch b/patches/0002-Use-older-API-to-avoid-requiring-API-v30.patch index 721e9eb..44f08fb 100644 --- a/patches/0002-Use-older-API-to-avoid-requiring-API-v30.patch +++ b/patches/0002-Use-older-API-to-avoid-requiring-API-v30.patch @@ -1,20 +1,20 @@ -From ec84856e0f0bc5a307529122bfed3d94d2ef4011 Mon Sep 17 00:00:00 2001 -From: Matthew Maurer <mmaurer@google.com> -Date: Thu, 24 Feb 2022 14:07:03 -0800 -Subject: [PATCH] Use older API to avoid requiring API v30 +From b5ee33076e1868c5946345b2cfb15a519b8c2577 Mon Sep 17 00:00:00 2001 +From: Jeff Vander Stoep <jeffv@google.com> +Date: Mon, 5 Dec 2022 12:42:22 +0100 +Subject: [PATCH 2/2] Use older API to avoid requiring API v30 Test: Check that keystore still outputs logs to system Bug: 221185310 -Change-Id: I25174f1617557e270db70cd432cec78c037c6b75 +Change-Id: If81d66cb145cbb41b4338fd64ac024d77243482e --- src/lib.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/lib.rs b/src/lib.rs -index d21be3f..bc4fa61 100644 +index 4bcce0c..59f942b 100644 --- a/src/lib.rs +++ b/src/lib.rs -@@ -113,17 +113,11 @@ impl LogId { +@@ -111,17 +111,11 @@ impl LogId { /// Output log to android system. #[cfg(target_os = "android")] fn android_log(log_id: log_ffi::log_id_t, prio: log_ffi::LogPriority, tag: &CStr, msg: &CStr) { @@ -37,5 +37,5 @@ index d21be3f..bc4fa61 100644 } -- -2.35.1.574.g5d30c73bfb-goog +2.39.0.rc0.267.gcb52ba06e7-goog @@ -13,13 +13,13 @@ //! #[macro_use] extern crate log; //! extern crate android_logger; //! -//! use log::Level; +//! use log::LevelFilter; //! use android_logger::Config; //! //! /// Android code may not have obvious "main", this is just an example. //! fn main() { //! android_logger::init_once( -//! Config::default().with_min_level(Level::Trace), +//! Config::default().with_max_level(LevelFilter::Trace), //! ); //! //! debug!("this is a debug {}", "message"); @@ -36,13 +36,13 @@ //! #[macro_use] extern crate log; //! extern crate android_logger; //! -//! use log::Level; +//! use log::LevelFilter; //! use android_logger::{Config,FilterBuilder}; //! //! fn main() { //! android_logger::init_once( //! Config::default() -//! .with_min_level(Level::Trace) +//! .with_max_level(LevelFilter::Trace) //! .with_tag("mytag") //! .with_filter(FilterBuilder::new().parse("debug,hello::crate=trace").build()), //! ); @@ -58,31 +58,29 @@ //! //! android_logger::init_once( //! Config::default() -//! .with_min_level(log::Level::Trace) +//! .with_max_level(log::LevelFilter::Trace) //! .format(|f, record| write!(f, "my_app: {}", record.args())) //! ) //! ``` #[cfg(target_os = "android")] extern crate android_log_sys as log_ffi; -#[macro_use] -extern crate lazy_static; +extern crate once_cell; +use once_cell::sync::OnceCell; #[macro_use] extern crate log; extern crate env_logger; -use std::sync::RwLock; - +use log::{Level, LevelFilter, Log, Metadata, Record}; #[cfg(target_os = "android")] use log_ffi::LogPriority; -use log::{Level, Log, Metadata, Record}; use std::ffi::{CStr, CString}; -use std::mem; use std::fmt; +use std::mem::{self, MaybeUninit}; use std::ptr; -pub use env_logger::filter::{Filter, Builder as FilterBuilder}; +pub use env_logger::filter::{Builder as FilterBuilder, Filter}; pub use env_logger::fmt::Formatter; pub(crate) type FormatFn = Box<dyn Fn(&mut dyn fmt::Write, &Record) -> fmt::Result + Sync + Send>; @@ -127,22 +125,24 @@ fn android_log(_log_id: Option<LogId>, _priority: Level, _tag: &CStr, _msg: &CSt /// Underlying android logger backend pub struct AndroidLogger { - config: RwLock<Config>, + config: OnceCell<Config>, } impl AndroidLogger { /// Create new logger instance from config pub fn new(config: Config) -> AndroidLogger { AndroidLogger { - config: RwLock::new(config), + config: OnceCell::from(config), } } -} -lazy_static! { - static ref ANDROID_LOGGER: AndroidLogger = AndroidLogger::default(); + fn config(&self) -> &Config { + self.config.get_or_init(Config::default) + } } +static ANDROID_LOGGER: OnceCell<AndroidLogger> = OnceCell::new(); + const LOGGING_TAG_MAX_LEN: usize = 23; const LOGGING_MSG_MAX_LEN: usize = 4000; @@ -150,34 +150,42 @@ impl Default for AndroidLogger { /// Create a new logger with default config fn default() -> AndroidLogger { AndroidLogger { - config: RwLock::new(Config::default()), + config: OnceCell::from(Config::default()), } } } impl Log for AndroidLogger { - fn enabled(&self, _: &Metadata) -> bool { - true + fn enabled(&self, metadata: &Metadata) -> bool { + let config = self.config(); + // todo: consider __android_log_is_loggable. + metadata.level() <= config.log_level.unwrap_or_else(log::max_level) } fn log(&self, record: &Record) { - let config = self.config - .read() - .expect("failed to acquire android_log filter lock for read"); + let config = self.config(); + + if !self.enabled(record.metadata()) { + return; + } + // this also checks the level, but only if a filter was + // installed. if !config.filter_matches(record) { return; } // tag must not exceed LOGGING_TAG_MAX_LEN - #[allow(deprecated)] // created an issue #35 for this - let mut tag_bytes: [u8; LOGGING_TAG_MAX_LEN + 1] = unsafe { mem::uninitialized() }; + let mut tag_bytes: [MaybeUninit<u8>; LOGGING_TAG_MAX_LEN + 1] = uninit_array(); let module_path = record.module_path().unwrap_or_default().to_owned(); // If no tag was specified, use module name let custom_tag = &config.tag; - let tag = custom_tag.as_ref().map(|s| s.as_bytes()).unwrap_or(module_path.as_bytes()); + let tag = custom_tag + .as_ref() + .map(|s| s.as_bytes()) + .unwrap_or_else(|| module_path.as_bytes()); // truncate the tag here to fit into LOGGING_TAG_MAX_LEN self.fill_tag_bytes(&mut tag_bytes, tag); @@ -207,53 +215,51 @@ impl Log for AndroidLogger { } impl AndroidLogger { - fn fill_tag_bytes(&self, array: &mut [u8], tag: &[u8]) { + fn fill_tag_bytes(&self, array: &mut [MaybeUninit<u8>], tag: &[u8]) { if tag.len() > LOGGING_TAG_MAX_LEN { - for (input, output) in tag.iter() + for (input, output) in tag + .iter() .take(LOGGING_TAG_MAX_LEN - 2) .chain(b"..\0".iter()) .zip(array.iter_mut()) { - *output = *input; + output.write(*input); } } else { - for (input, output) in tag.iter() - .chain(b"\0".iter()) - .zip(array.iter_mut()) - { - *output = *input; + for (input, output) in tag.iter().chain(b"\0".iter()).zip(array.iter_mut()) { + output.write(*input); } } } } /// Filter for android logger. +#[derive(Default)] pub struct Config { - log_level: Option<Level>, + log_level: Option<LevelFilter>, log_id: Option<LogId>, filter: Option<env_logger::filter::Filter>, tag: Option<CString>, custom_format: Option<FormatFn>, } -impl Default for Config { - fn default() -> Self { - Config { - log_level: None, - log_id: None, - filter: None, - tag: None, - custom_format: None, - } +impl Config { + // TODO: Remove on 0.13 version release. + /// **DEPRECATED**, use [`Config::with_max_level()`] instead. + #[deprecated(note = "use `.with_max_level()` instead")] + pub fn with_min_level(self, level: Level) -> Self { + self.with_max_level(level.to_level_filter()) } -} -impl Config { - /// Change the minimum log level. + /// Changes the maximum log level. /// - /// All values above the set level are logged. For example, if - /// `Warn` is set, the `Error` is logged too, but `Info` isn't. - pub fn with_min_level(mut self, level: Level) -> Self { + /// Note, that `Trace` is the maximum level, because it provides the + /// maximum amount of detail in the emitted logs. + /// + /// If `Off` level is provided, then nothing is logged at all. + /// + /// [`log::max_level()`] is considered as the default level. + pub fn with_max_level(mut self, level: LevelFilter) -> Self { self.log_level = Some(level); self } @@ -269,7 +275,7 @@ impl Config { fn filter_matches(&self, record: &Record) -> bool { if let Some(ref filter) = self.filter { - filter.matches(&record) + filter.matches(record) } else { true } @@ -290,7 +296,7 @@ impl Config { /// # use android_logger::Config; /// android_logger::init_once( /// Config::default() - /// .with_min_level(log::Level::Trace) + /// .with_max_level(log::LevelFilter::Trace) /// .format(|f, record| write!(f, "my_app: {}", record.args())) /// ) /// ``` @@ -303,35 +309,46 @@ impl Config { } } -struct PlatformLogWriter<'a> { - #[cfg(target_os = "android")] priority: LogPriority, - #[cfg(not(target_os = "android"))] priority: Level, +pub struct PlatformLogWriter<'a> { + #[cfg(target_os = "android")] + 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, - buffer: [u8; LOGGING_MSG_MAX_LEN + 1], + buffer: [MaybeUninit<u8>; LOGGING_MSG_MAX_LEN + 1], } impl<'a> PlatformLogWriter<'a> { #[cfg(target_os = "android")] - pub fn new(log_id: Option<LogId>, level: Level, 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: match level { + priority, + log_id: LogId::to_native(log_id), + len: 0, + last_newline_index: 0, + tag, + buffer: uninit_array(), + } + } + + #[cfg(target_os = "android")] + 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, Level::Debug => LogPriority::DEBUG, Level::Error => LogPriority::ERROR, Level::Trace => LogPriority::VERBOSE, }, - log_id: LogId::to_native(log_id), - len: 0, - last_newline_index: 0, tag, - buffer: unsafe { mem::uninitialized() }, - } + ) } #[cfg(not(target_os = "android"))] @@ -343,7 +360,7 @@ impl<'a> PlatformLogWriter<'a> { len: 0, last_newline_index: 0, tag, - buffer: unsafe { mem::uninitialized() }, + buffer: uninit_array(), } } @@ -375,7 +392,7 @@ impl<'a> PlatformLogWriter<'a> { } /// Flush everything remaining to android logger. - fn flush(&mut self) { + pub fn flush(&mut self) { let total_len = self.len; if total_len == 0 { @@ -389,21 +406,22 @@ impl<'a> PlatformLogWriter<'a> { /// Output buffer up until the \0 which will be placed at `len` position. fn output_specified_len(&mut self, len: usize) { - let mut last_byte: u8 = b'\0'; + let mut last_byte = MaybeUninit::new(b'\0'); + mem::swap(&mut last_byte, unsafe { self.buffer.get_unchecked_mut(len) }); - let msg: &CStr = unsafe { CStr::from_ptr(mem::transmute(self.buffer.as_ptr())) }; + let msg: &CStr = unsafe { CStr::from_ptr(self.buffer.as_ptr().cast()) }; android_log(self.log_id, self.priority, self.tag, msg); - *unsafe { self.buffer.get_unchecked_mut(len) } = last_byte; + unsafe { *self.buffer.get_unchecked_mut(len) = last_byte }; } /// Copy `len` bytes from `index` position to starting position. fn copy_bytes_to_start(&mut self, index: usize, len: usize) { - let src = unsafe { self.buffer.as_ptr().offset(index as isize) }; let dst = self.buffer.as_mut_ptr(); + let src = unsafe { self.buffer.as_ptr().add(index) }; unsafe { ptr::copy(src, dst, len) }; } } @@ -422,7 +440,7 @@ impl<'a> fmt::Write for PlatformLogWriter<'a> { .zip(incomming_bytes) .enumerate() .fold(None, |acc, (i, (output, input))| { - *output = *input; + output.write(*input); if *input == b'\n' { Some(i) } else { @@ -460,7 +478,9 @@ impl<'a> fmt::Write for PlatformLogWriter<'a> { /// This action does not require initialization. However, without initialization it /// will use the default filter, which allows all logs. pub fn log(record: &Record) { - ANDROID_LOGGER.log(record) + ANDROID_LOGGER + .get_or_init(AndroidLogger::default) + .log(record) } /// Initializes the global logger with an android logger. @@ -471,19 +491,22 @@ pub fn log(record: &Record) { /// It is ok to call this at the activity creation, and it will be /// repeatedly called on every lifecycle restart (i.e. screen rotation). pub fn init_once(config: Config) { - if let Err(err) = log::set_logger(&*ANDROID_LOGGER) { + let log_level = config.log_level; + let logger = ANDROID_LOGGER.get_or_init(|| AndroidLogger::new(config)); + + if let Err(err) = log::set_logger(logger) { debug!("android_logger: log::set_logger failed: {}", err); - } else { - if let Some(level) = config.log_level { - log::set_max_level(level.to_level_filter()); - } - *ANDROID_LOGGER - .config - .write() - .expect("failed to acquire android_log filter lock for write") = config; + } else if let Some(level) = log_level { + log::set_max_level(level); } } +// FIXME: When `maybe_uninit_uninit_array ` is stabilized, use it instead of this helper +fn uninit_array<const N: usize, T>() -> [MaybeUninit<T>; N] { + // SAFETY: Array contains MaybeUninit, which is fine to be uninit + unsafe { MaybeUninit::uninit().assume_init() } +} + #[cfg(test)] mod tests { use super::*; @@ -494,11 +517,11 @@ mod tests { fn check_config_values() { // Filter is checked in config_filter_match below. let config = Config::default() - .with_min_level(Level::Trace) + .with_max_level(LevelFilter::Trace) .with_log_id(LogId::System) .with_tag("my_app"); - assert_eq!(config.log_level, Some(Level::Trace)); + 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())); } @@ -507,7 +530,7 @@ mod tests { fn log_calls_formatter() { static FORMAT_FN_WAS_CALLED: AtomicBool = AtomicBool::new(false); let config = Config::default() - .with_min_level(Level::Info) + .with_max_level(LevelFilter::Info) .format(|_, _| { FORMAT_FN_WAS_CALLED.store(true, Ordering::SeqCst); Ok(()) @@ -520,10 +543,12 @@ mod tests { } #[test] - fn logger_always_enabled() { - let logger = AndroidLogger::new(Config::default()); + fn logger_enabled_threshold() { + let logger = AndroidLogger::new(Config::default().with_max_level(LevelFilter::Info)); - assert!(logger.enabled(&log::MetadataBuilder::new().build())); + assert!(logger.enabled(&log::MetadataBuilder::new().level(Level::Warn).build())); + assert!(logger.enabled(&log::MetadataBuilder::new().level(Level::Info).build())); + assert!(!logger.enabled(&log::MetadataBuilder::new().level(Level::Debug).build())); } // Test whether the filter gets called correctly. Not meant to be exhaustive for all filter @@ -545,12 +570,12 @@ mod tests { let logger = AndroidLogger::new(Config::default()); let too_long_tag: [u8; LOGGING_TAG_MAX_LEN + 20] = [b'a'; LOGGING_TAG_MAX_LEN + 20]; - let mut result: [u8; LOGGING_TAG_MAX_LEN + 1] = Default::default(); + let mut result: [MaybeUninit<u8>; LOGGING_TAG_MAX_LEN + 1] = uninit_array(); logger.fill_tag_bytes(&mut result, &too_long_tag); let mut expected_result = [b'a'; LOGGING_TAG_MAX_LEN - 2].to_vec(); expected_result.extend("..\0".as_bytes()); - assert_eq!(result.to_vec(), expected_result); + assert_eq!(unsafe { assume_init_slice(&result) }, expected_result); } #[test] @@ -558,19 +583,19 @@ mod tests { let logger = AndroidLogger::new(Config::default()); let short_tag: [u8; 3] = [b'a'; 3]; - let mut result: [u8; LOGGING_TAG_MAX_LEN + 1] = Default::default(); + let mut result: [MaybeUninit<u8>; LOGGING_TAG_MAX_LEN + 1] = uninit_array(); logger.fill_tag_bytes(&mut result, &short_tag); let mut expected_result = short_tag.to_vec(); expected_result.push(0); - assert_eq!(result.to_vec()[..4], expected_result); + assert_eq!(unsafe { assume_init_slice(&result[..4]) }, expected_result); } #[test] fn platform_log_writer_init_values() { let tag = CStr::from_bytes_with_nul(b"tag\0").unwrap(); - let writer = PlatformLogWriter::new(None, 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 @@ -591,7 +616,10 @@ mod tests { // Should have flushed up until the last newline. assert_eq!(writer.len, 3); assert_eq!(writer.last_newline_index, 0); - assert_eq!(&writer.buffer.to_vec()[..writer.len], "\n90".as_bytes()); + assert_eq!( + unsafe { assume_init_slice(&writer.buffer[..writer.len]) }, + "\n90".as_bytes() + ); writer.temporal_flush(); // Should have flushed all remaining bytes. @@ -634,7 +662,7 @@ mod tests { writer.output_specified_len(5); assert_eq!( - writer.buffer[..log_string.len()].to_vec(), + unsafe { assume_init_slice(&writer.buffer[..log_string.len()]) }, log_string.as_bytes() ); } @@ -648,7 +676,10 @@ mod tests { writer.copy_bytes_to_start(3, 2); - assert_eq!(writer.buffer[..10].to_vec(), "3423456789".as_bytes()); + assert_eq!( + unsafe { assume_init_slice(&writer.buffer[..10]) }, + "3423456789".as_bytes() + ); } #[test] @@ -663,12 +694,16 @@ mod tests { writer.copy_bytes_to_start(10, 0); assert_eq!( - writer.buffer[..test_string.len()].to_vec(), + unsafe { assume_init_slice(&writer.buffer[..test_string.len()]) }, test_string.as_bytes() ); } fn get_tag_writer() -> PlatformLogWriter<'static> { - PlatformLogWriter::new(None, 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] { + &*(slice as *const [MaybeUninit<T>] as *const [T]) } } diff --git a/tests/config_log_level.rs b/tests/config_log_level.rs index ca6ad59..864b229 100644 --- a/tests/config_log_level.rs +++ b/tests/config_log_level.rs @@ -3,7 +3,9 @@ extern crate log; #[test] fn config_log_level() { - android_logger::init_once(android_logger::Config::default().with_min_level(log::Level::Trace)); + android_logger::init_once( + android_logger::Config::default().with_max_level(log::LevelFilter::Trace), + ); assert_eq!(log::max_level(), log::LevelFilter::Trace); -}
\ No newline at end of file +} diff --git a/tests/default_init.rs b/tests/default_init.rs index e7ca9e2..7b04c24 100644 --- a/tests/default_init.rs +++ b/tests/default_init.rs @@ -7,4 +7,4 @@ fn default_init() { // android_logger has default log level "off" assert_eq!(log::max_level(), log::LevelFilter::Off); -}
\ No newline at end of file +} diff --git a/tests/multiple_init.rs b/tests/multiple_init.rs index 99b58c8..26f815d 100644 --- a/tests/multiple_init.rs +++ b/tests/multiple_init.rs @@ -3,10 +3,14 @@ extern crate log; #[test] fn multiple_init() { - android_logger::init_once(android_logger::Config::default().with_min_level(log::Level::Trace)); + android_logger::init_once( + android_logger::Config::default().with_max_level(log::LevelFilter::Trace), + ); // Second initialization should be silently ignored - android_logger::init_once(android_logger::Config::default().with_min_level(log::Level::Error)); + android_logger::init_once( + android_logger::Config::default().with_max_level(log::LevelFilter::Error), + ); assert_eq!(log::max_level(), log::LevelFilter::Trace); -}
\ No newline at end of file +} |