diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9bcb4d3..da17594 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,6 +41,7 @@ jobs: components: rustfmt, clippy - run: cargo fmt --check + - run: cargo clippy --target=${{ matrix.target }} ${{ matrix.features }} -- -Dwarnings - run: cargo build --target=${{ matrix.target }} ${{ matrix.features }} - run: cargo doc --target=${{ matrix.target }} ${{ matrix.features }} env: diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a75dac..8f0dd63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All user visible changes to this project will be documented in this file. This project uses [Semantic Versioning 2.0.0]. +## [TODO] + +- Remove `max_level` in favour of extracting it from the `Filter` + +// TODO: bunch of releases are missing? + diff --git a/README.md b/README.md index 15a28f7..edbd076 100644 --- a/README.md +++ b/README.md @@ -7,74 +7,77 @@ This library is a drop-in replacement for `env_logger`. Instead, it outputs messages to android's logcat. -This only works on Android and requires linking to `log` which -is only available under android. With Cargo, it is possible to conditionally require -this library: +This only works on Android and requires linking to `liblog` which +is only available under Android. With Cargo, it is possible to conditionally +include this crate and library requirement when targeting Android only: ```toml [target.'cfg(target_os = "android")'.dependencies] android_logger = "0.15" ``` -Example of initialization on activity creation, with log configuration: +### Examples -```rust -#[macro_use] extern crate log; -extern crate android_logger; +#### Example of initialization on activity creation, with log configuration -use log::LevelFilter; -use android_logger::{Config,FilterBuilder}; +```rust +use android_logger::Config; fn native_activity_create() { android_logger::init_once( Config::default() - .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() - .parse("debug,hello::crate=error") - .build()) + .parse_filters("debug,hello::crate=error") // Limig log level to Debug, and limit the hello::crate module further to Error. ); - trace!("this is a verbose {}", "message"); - error!("this is printed by default"); + log::debug!("this is a verbose {}", "message"); + log::error!("this is printed by default"); } ``` -To allow all logs, use the default configuration with min level Trace: +To allow all logs, use the default configuration with the global module level set to `Trace` ```rust -#[macro_use] extern crate log; -extern crate android_logger; - -use log::LevelFilter; use android_logger::Config; fn native_activity_create() { android_logger::init_once( - Config::default().with_max_level(LevelFilter::Trace), + Config::default().filter_level(log::LevelFilter::Trace), ); } ``` +#### Example with a custom log formatter + +```rust +use android_logger::Config; + +android_logger::init_once( + Config::default() + .format(|f, record| write!(f, "my_app: {}", record.args())) +) +``` + +### Single-initialization guarantee + There is a caveat that this library can only be initialized once (hence the `init_once` function name). However, Android native activity can be re-created every time the screen is rotated, resulting in multiple initialization calls. Therefore this library will only log a warning for subsequent `init_once` calls. +### + This library ensures that logged messages do not overflow Android log message limits by efficiently splitting messages into chunks. -## Consistent log filtering in mixed Rust/C/C++ apps +### Consistent log filtering in mixed Rust/C/C++ apps -Android's C logging API determines the effective log level based on [a -combination](https://cs.android.com/android/platform/superproject/main/+/main:system/logging/liblog/properties.cpp;l=243;drc=b74a506c1b69f5b295a8cdfd7e2da3b16db15934) -of a process-wide global variable, [system-wide -properties](https://cs.android.com/android/platform/superproject/main/+/main:system/logging/logd/README.property;l=45;drc=99c545d3098018a544cb292e1501daca694bee0f), -and call-specific default. `log` + `android_logger` crates add another layer of -log filtering on top of that, independent from the C API. +Android's C logging API determines the effective log level based on [the combination] of a process-wide global variable, [system-wide properties], and call-specific default. `log` + `android_logger` crates add another layer of log filtering on top of that, independent from the C API. -``` +[the combination]: https://cs.android.com/android/platform/superproject/main/+/main:system/logging/liblog/properties.cpp;l=243;drc=b74a506c1b69f5b295a8cdfd7e2da3b16db15934 +[system-wide properties]: https://cs.android.com/android/platform/superproject/main/+/main:system/logging/logd/README.property;l=45;drc=99c545d3098018a544cb292e1501daca694bee0f + +```text .-----. | app | '-----' Rust @@ -97,23 +100,24 @@ C/C++ | '--------------. ``` `liblog` APIs introduced in Android API 30 let `android_logger` delegate log -filtering decision to `liblog`, making the log level consistent across C, C++ +filtering decisions to `liblog`, making the log level consistent across C, C++ and Rust calls. -If you build `android_logger` with `android-api-30` feature enabled, the logger +If you build `android_logger` with the `android-api-30` feature enabled, the logger will consider the process-wide global state (set via [`__android_log_set_minimum_priority`](https://cs.android.com/android/platform/superproject/main/+/main:prebuilts/runtime/mainline/runtime/sdk/common_os/include/system/logging/liblog/include/android/log.h;l=364;drc=4cf460634134d51dba174f8af60dffb10f703f51)) and Android system properties when deciding if a message should be logged or not. In this case, the effective log level is the _least verbose_ of the levels -set between those and [Rust log -facilities](https://docs.rs/log/latest/log/fn.set_max_level.html). +set between those and [Rust log facilities]. + +[Rust log facilities]: https://docs.rs/log/latest/log/fn.set_max_level.html -## License +### License Licensed under either of - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or ) at your option. diff --git a/examples/system_log_level_overrides.rs b/examples/system_log_level_overrides.rs index 3120b1d..d04cc67 100644 --- a/examples/system_log_level_overrides.rs +++ b/examples/system_log_level_overrides.rs @@ -1,4 +1,4 @@ -//! An utility for testing the behavior of `android_logger` crate. +//! An utility for testing the behavior of the `android_logger` crate. //! //! ## Build //! @@ -37,7 +37,7 @@ //! HOME=$PWD bin/launch_cvd //! ``` //! -//! Once emulator launches, `adb` should detect it on `0.0.0.0:6520` +//! Once the emulator launches, `adb` should detect it on `0.0.0.0:6520` //! automatically. Shut down the `launch_cvd` command to exit the emulator. //! //! 3. Upload & run: @@ -55,7 +55,7 @@ //! //! ``` //! # default: should print info+ logs in `adb logcat -s log_test` -//! # hint: use `adb logcat -v color` is awesome too +//! # hint: `adb logcat -v color` is awesome too //! adb shell /data/local/tmp/system_log_level_overrides //! //! # should print trace+ logs in `adb logcat -s log_test` @@ -71,9 +71,10 @@ fn main() { android_logger::init_once( android_logger::Config::default() .with_tag("log_test") - // If set, this is the highest level to log unless overriddeby by the system. - // Note the verbosity can be *increased* through system properties. - .with_max_level(log::LevelFilter::Info), + // If set, this is the highest level to log unless overridden by the system. + // Note the verbosity can be *increased* through system properties, as long + // as it is also increased in the `log` crate (see the override below). + .filter_level(log::LevelFilter::Info), ); // The log crate applies its filtering before we even get to android_logger. // Pass everything down so that Android's liblog can determine the log level instead. diff --git a/src/config.rs b/src/config.rs index bd14f58..0df93f7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -4,19 +4,33 @@ use std::ffi::CString; use std::fmt; /// Filter for android logger. -#[derive(Default)] +// #[derive(Default)] +// TODO: Rename to Builder. pub struct Config { - pub(crate) log_level: Option, pub(crate) buf_id: Option, - filter: Option, + pub(crate) filter: env_filter::Builder, pub(crate) tag: Option, pub(crate) custom_format: Option, } +impl Default for Config { + /// Creates a default config that logs all modules at the [`LevelFilter::Error`] level by + /// default, when no other filters are set. + // TODO: Parse from env? + fn default() -> Self { + Self { + buf_id: None, + // TODO: This doesn't read from an env var like RUST_LOG... + filter: env_filter::Builder::new(), + tag: None, + custom_format: None, + } + } +} + impl fmt::Debug for Config { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Config") - .field("log_level", &self.log_level) .field("buf_id", &self.buf_id) .field("filter", &self.filter) .field("tag", &self.tag) @@ -62,39 +76,32 @@ fn android_is_loggable_len( } #[cfg(not(all(target_os = "android", feature = "android-api-30")))] -fn default_is_loggable(_tag: &str, record_level: Level, config_level: Option) -> bool { - record_level <= config_level.unwrap_or_else(log::max_level) +pub(crate) fn is_loggable(_tag: &str, _record_level: Level) -> bool { + // There is nothing to test here, the `log` macros already checked the variable + // `log::max_level()` before calling into the implementation. + // The tests ensure this by creating and calling into `AndroidLogger::log()` without + // `set_max_level()` from `init_once()`, and expect the message to be logged. + true } #[cfg(all(target_os = "android", feature = "android-api-30"))] -fn android_is_loggable(tag: &str, record_level: Level, config_level: Option) -> bool { +pub(crate) fn is_loggable(tag: &str, record_level: Level) -> bool { let prio = android_log_priority_from_level(record_level); // Priority to use in case no system-wide or process-wide overrides are set. - let default_prio = match config_level { - Some(level_filter) => match level_filter.to_level() { - Some(level) => android_log_priority_from_level(level), - // LevelFilter::to_level() returns None only for LevelFilter::Off - None => android_log_sys::LogPriority::SILENT, - }, - None => android_log_sys::LogPriority::INFO, + // WARNING: Reading live `log::max_level()` state here would break tests, for example when + // `AndroidLogger` is constructed and `AndroidLogger::log()` is called _without_ going through + // `init_once()` which would call `log::set_max_level()`, leaving this at `Off`. Currently no + // tests exist that run on live Android devices and/or mock `__android_log_is_loggable_len()` + // such that this function can be called. + let default_prio = match log::max_level().to_level() { + Some(level) => android_log_priority_from_level(level), + // LevelFilter::to_level() returns None only for LevelFilter::Off + None => android_log_sys::LogPriority::SILENT, }; android_is_loggable_len(prio, tag, default_prio) } impl Config { - /// Changes the maximum log level. - /// - /// 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 - } - /// Changes the Android logging system buffer to be used. /// /// By default, logs are sent to the [`Main`] log. Other logging buffers may @@ -106,25 +113,26 @@ impl Config { self } - pub(crate) fn filter_matches(&self, record: &Record) -> bool { - if let Some(ref filter) = self.filter { - filter.matches(record) - } else { - true - } + /// Adds a directive to the filter for a specific module. + /// + /// Note that this replaces the default [`LevelFilter::Error`] for all global modules. + pub fn filter_module(mut self, module: &str, level: LevelFilter) -> Self { + self.filter.filter_module(module, level); + self } - pub(crate) fn is_loggable(&self, tag: &str, level: Level) -> bool { - #[cfg(all(target_os = "android", feature = "android-api-30"))] - use android_is_loggable as is_loggable; - #[cfg(not(all(target_os = "android", feature = "android-api-30")))] - use default_is_loggable as is_loggable; - - is_loggable(tag, level, self.log_level) + /// Adds a directive to the filter for all modules. + pub fn filter_level(mut self, level: LevelFilter) -> Self { + self.filter.filter_level(level); + self } - pub fn with_filter(mut self, filter: env_filter::Filter) -> Self { - self.filter = Some(filter); + /// Parses the directives string in the same form as the `RUST_LOG` + /// environment variable. + /// + /// See the `env_logger` module documentation for more details. + pub fn parse_filters(mut self, filters: &str) -> Self { + self.filter.parse(filters); self } @@ -138,7 +146,6 @@ impl Config { /// # use android_logger::Config; /// android_logger::init_once( /// Config::default() - /// .with_max_level(log::LevelFilter::Trace) /// .format(|f, record| write!(f, "my_app: {}", record.args())) /// ) /// ``` diff --git a/src/lib.rs b/src/lib.rs index 9597ae8..b896dad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,67 +5,12 @@ // http://opensource.org/licenses/MIT>, at your option. This file may not be // copied, modified, or distributed except according to those terms. -//! A logger which writes to android output. -//! -//! ## Example -//! -//! ``` -//! #[macro_use] extern crate log; -//! extern crate android_logger; -//! -//! 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_max_level(LevelFilter::Trace), -//! ); -//! -//! debug!("this is a debug {}", "message"); -//! error!("this is printed by default"); -//! } -//! ``` -//! -//! ## Example with module path filter -//! -//! It is possible to limit log messages to output from a specific crate, -//! and override the logcat tag name (by default, the crate name is used): -//! -//! ``` -//! #[macro_use] extern crate log; -//! extern crate android_logger; -//! -//! use log::LevelFilter; -//! use android_logger::{Config,FilterBuilder}; -//! -//! fn main() { -//! android_logger::init_once( -//! Config::default() -//! .with_max_level(LevelFilter::Trace) -//! .with_tag("mytag") -//! .with_filter(FilterBuilder::new().parse("debug,hello::crate=trace").build()), -//! ); -//! -//! // .. -//! } -//! ``` -//! -//! ## Example with a custom log formatter -//! -//! ``` -//! use android_logger::Config; -//! -//! android_logger::init_once( -//! Config::default() -//! .with_max_level(log::LevelFilter::Trace) -//! .format(|f, record| write!(f, "my_app: {}", record.args())) -//! ) -//! ``` +#![doc = include_str!("../README.md")] #[cfg(target_os = "android")] extern crate android_log_sys as log_ffi; +use config::is_loggable; use log::{Log, Metadata, Record}; use std::ffi::{CStr, CString}; use std::fmt; @@ -119,30 +64,36 @@ fn android_log( #[cfg(not(target_os = "android"))] fn android_log(_buf_id: Option, _priority: log::Level, _tag: &CStr, _msg: &CStr) {} -/// Underlying android logger backend -#[derive(Debug, Default)] +/// Underlying Android logger backend +#[derive(Debug)] pub struct AndroidLogger { - config: OnceLock, + filter: env_filter::Filter, + config: Config, +} + +impl Default for AndroidLogger { + /// Create new logger instance using the [default `Cofig`][Config::default()]. + fn default() -> Self { + Self::new(Config::default()) + } } impl AndroidLogger { /// Create new logger instance from config - pub fn new(config: Config) -> AndroidLogger { + pub fn new(mut config: Config) -> AndroidLogger { AndroidLogger { - config: OnceLock::from(config), + // TODO: This consumes the filter from the config, disallowing it to be reused... + filter: config.filter.build(), + config, } } - - fn config(&self) -> &Config { - self.config.get_or_init(Config::default) - } } static ANDROID_LOGGER: OnceLock = OnceLock::new(); /// Maximum length of a tag that does not require allocation. /// -/// Tags configured explicitly in [Config] will not cause an extra allocation. When the tag is +/// Tags configured explicitly in [`Config`] will not cause an extra allocation. When the tag is /// derived from the module path, paths longer than this limit will trigger an allocation for each /// log statement. /// @@ -151,21 +102,20 @@ const LOGGING_TAG_MAX_LEN: usize = 127; const LOGGING_MSG_MAX_LEN: usize = 4000; impl Log for AndroidLogger { + /// # Warning + /// This method relies on stateful data when `android-api-30` is enabled, including + /// [`log::max_level()`] which we only initialize when [`init_once()`] is called and which can + /// be changed by the user at any point via [`log::set_max_level()`]. fn enabled(&self, metadata: &Metadata) -> bool { - self.config() - .is_loggable(metadata.target(), metadata.level()) + is_loggable(metadata.target(), metadata.level()) } fn log(&self, record: &Record) { - 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) { + if !self.filter.matches(record) { return; } @@ -177,7 +127,7 @@ impl Log for AndroidLogger { let module_path = record.module_path().unwrap_or_default(); - let tag = if let Some(tag) = &config.tag { + let tag = if let Some(tag) = &self.config.tag { tag } else if module_path.len() < tag_bytes.len() { fill_tag_bytes(&mut tag_bytes, module_path.as_bytes()) @@ -190,16 +140,14 @@ 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(config.buf_id, record.level(), tag); + let mut writer = PlatformLogWriter::new(self.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. - let _ = match (&config.tag, &config.custom_format) { + use std::fmt::Write; + let _ = match (&self.config.tag, &self.config.custom_format) { (_, Some(format)) => format(&mut writer, record), - (Some(_), _) => fmt::write( - &mut writer, - format_args!("{}: {}", module_path, *record.args()), - ), + (Some(_), _) => write!(&mut writer, "{}: {}", module_path, *record.args()), _ => fmt::write(&mut writer, *record.args()), }; @@ -210,30 +158,38 @@ impl Log for AndroidLogger { fn flush(&self) {} } -/// Send a log record to Android logging backend. +/// Send a log record to the Android logging backend. /// -/// This action does not require initialization. However, without initialization it -/// will use the default filter, which allows all logs. +/// This action does not require initialization, and does not initialize the [`mod@log`] framework +/// to redirect all logs to [`AndroidLogger`]. If not otherwise configured earlier using +/// [`init_once()`] this uses the default [`Config`] with [`log::LevelFilter::Error`]. pub fn log(record: &Record) { - ANDROID_LOGGER - .get_or_init(AndroidLogger::default) - .log(record) + let logger = ANDROID_LOGGER.get_or_init(|| AndroidLogger::new(Default::default())); + logger.log(record); } -/// Initializes the global logger with an android logger. +/// Initializes the global logger with an Android logger. /// /// This can be called many times, but will only initialize logging once, /// and will not replace any other previously initialized logger. /// /// It is ok to call this at the activity creation, and it will be /// repeatedly called on every lifecycle restart (i.e. screen rotation). +/// +/// # Warning +/// `config` is ignored on subsequent calls to either [`init_once()`] or [`log()`]. pub fn init_once(config: Config) { - let log_level = config.log_level; let logger = ANDROID_LOGGER.get_or_init(|| AndroidLogger::new(config)); + // TODO: Only continue if ANDROID_LOGGER was None? + + let log_level = logger.filter.filter(); + if let Err(err) = log::set_logger(logger) { - log::debug!("android_logger: log::set_logger failed: {}", err); - } else if let Some(level) = log_level { - log::set_max_level(level); + // TODO: Bubble up the error (try_init()) or panic (init()), as suggested + // by the `log` crate and as implemented by `env_logger`. + log::debug!("android_logger: log::set_logger failed: {err}"); + } else { + log::set_max_level(log_level); } } diff --git a/src/platform_log_writer.rs b/src/platform_log_writer.rs index 2a7b53a..41de29d 100644 --- a/src/platform_log_writer.rs +++ b/src/platform_log_writer.rs @@ -192,12 +192,11 @@ pub mod tests { use crate::arrays::slice_assume_init_ref; use crate::platform_log_writer::PlatformLogWriter; use log::Level; - use std::ffi::CStr; use std::fmt::Write; #[test] fn platform_log_writer_init_values() { - let tag = CStr::from_bytes_with_nul(b"tag\0").unwrap(); + let tag = c"tag"; let writer = PlatformLogWriter::new(None, Level::Warn, tag); @@ -318,10 +317,6 @@ pub mod tests { } 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, c"tag") } } diff --git a/src/tests.rs b/src/tests.rs index 562a12f..c3138f2 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,16 +1,15 @@ -use super::*; use log::LevelFilter; + +use super::*; use std::sync::atomic::{AtomicBool, Ordering}; #[test] fn check_config_values() { // 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())); } @@ -18,27 +17,33 @@ fn check_config_values() { #[test] fn log_calls_formatter() { static FORMAT_FN_WAS_CALLED: AtomicBool = AtomicBool::new(false); - let config = Config::default() - .with_max_level(LevelFilter::Info) - .format(|_, _| { - FORMAT_FN_WAS_CALLED.store(true, Ordering::SeqCst); - Ok(()) - }); + let config = Config::default().format(|_, _| { + FORMAT_FN_WAS_CALLED.store(true, Ordering::SeqCst); + Ok(()) + }); let logger = AndroidLogger::new(config); - logger.log(&Record::builder().level(log::Level::Info).build()); + logger.log(&Record::builder().level(log::Level::Error).build()); assert!(FORMAT_FN_WAS_CALLED.load(Ordering::SeqCst)); } -#[test] -fn logger_enabled_threshold() { - let logger = AndroidLogger::new(Config::default().with_max_level(LevelFilter::Info)); - - assert!(logger.enabled(&log::MetadataBuilder::new().level(log::Level::Warn).build())); - assert!(logger.enabled(&log::MetadataBuilder::new().level(log::Level::Info).build())); - assert!(!logger.enabled(&log::MetadataBuilder::new().level(log::Level::Debug).build())); -} +// TODO: How about deleting `fn enabled()` pretty much entirely? It's only useful for implementing +// the new `android-api-30` `__android_log_is_loggable_len()` and without tests mocking that, +// bogus to call. All filtering based on `log::max_level()` happens inside the `log::log!()` +// macros already, and otherwise relies on the tests to call `init_once()` to ensure we call +// `log::set_max_level()`. +// +// #[test] +// fn logger_enabled_threshold() { +// let logger = AndroidLogger::new( +// Config::default().with_filter(FilterBuilder::new().filter_level(LevelFilter::Info).build()), +// ); + +// assert!(logger.enabled(&log::MetadataBuilder::new().level(log::Level::Warn).build())); +// assert!(logger.enabled(&log::MetadataBuilder::new().level(log::Level::Info).build())); +// assert!(!logger.enabled(&log::MetadataBuilder::new().level(log::Level::Debug).build())); +// } // Test whether the filter gets called correctly. Not meant to be exhaustive for all filter // options, as these are handled directly by the filter itself. @@ -47,11 +52,11 @@ fn config_filter_match() { let info_record = Record::builder().level(log::Level::Info).build(); let debug_record = Record::builder().level(log::Level::Debug).build(); - let info_all_filter = env_filter::Builder::new().parse("info").build(); - let info_all_config = Config::default().with_filter(info_all_filter); + let info_all_config = Config::default().filter_level(LevelFilter::Info); + let info_all_config = AndroidLogger::new(info_all_config); - assert!(info_all_config.filter_matches(&info_record)); - assert!(!info_all_config.filter_matches(&debug_record)); + assert!(info_all_config.filter.matches(&info_record)); + assert!(!info_all_config.filter.matches(&debug_record)); } #[test] diff --git a/tests/config_log_level.rs b/tests/config_log_level.rs index 864b229..b678d9d 100644 --- a/tests/config_log_level.rs +++ b/tests/config_log_level.rs @@ -1,11 +1,8 @@ -extern crate android_logger; -extern crate log; +use log::LevelFilter; #[test] fn config_log_level() { - android_logger::init_once( - android_logger::Config::default().with_max_level(log::LevelFilter::Trace), - ); + android_logger::init_once(android_logger::Config::default().filter_level(LevelFilter::Trace)); assert_eq!(log::max_level(), log::LevelFilter::Trace); } diff --git a/tests/default_init.rs b/tests/default_init.rs index 7b04c24..1c948cc 100644 --- a/tests/default_init.rs +++ b/tests/default_init.rs @@ -1,10 +1,8 @@ -extern crate android_logger; -extern crate log; - #[test] fn default_init() { android_logger::init_once(Default::default()); - // android_logger has default log level "off" - assert_eq!(log::max_level(), log::LevelFilter::Off); + // android_logger has default log level of Error + // TODO: env_logger/env_filter have this too, but I cannot find it in the source code + assert_eq!(log::max_level(), log::LevelFilter::Error); } diff --git a/tests/multiple_init.rs b/tests/multiple_init.rs index 26f815d..5150b91 100644 --- a/tests/multiple_init.rs +++ b/tests/multiple_init.rs @@ -1,16 +1,11 @@ -extern crate android_logger; -extern crate log; +use log::LevelFilter; #[test] fn multiple_init() { - android_logger::init_once( - android_logger::Config::default().with_max_level(log::LevelFilter::Trace), - ); + android_logger::init_once(android_logger::Config::default().filter_level(LevelFilter::Trace)); // Second initialization should be silently ignored - android_logger::init_once( - android_logger::Config::default().with_max_level(log::LevelFilter::Error), - ); + android_logger::init_once(android_logger::Config::default().filter_level(LevelFilter::Error)); - assert_eq!(log::max_level(), log::LevelFilter::Trace); + assert_eq!(log::max_level(), LevelFilter::Trace); }