Replace ESP_LOGLEVEL and ESP_LOGFILTERby ESP_LOG (#2291)
* Replace `ESP_LOGLEVEL` and `ESP_LOGFILTER`by `ESP_LOG` * CHANGELOG.md * Clippy * Fail build if using the now unsupported env variables
This commit is contained in:
parent
038d07f5b6
commit
ca5e8560bf
@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Added
|
||||
|
||||
### Changed
|
||||
- Replace environment variables `ESP_LOGLEVEL` and `ESP_LOGFILTER` with just one environment variable: `ESP_LOG` (#2291)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ portable-atomic = { version = "1.7.0", optional = true, default-features = fal
|
||||
|
||||
[build-dependencies]
|
||||
esp-build = { version = "0.1.0", path = "../esp-build" }
|
||||
log = "0.4.20"
|
||||
|
||||
[features]
|
||||
default = ["critical-section", "colors", "auto"]
|
||||
|
||||
@ -76,8 +76,7 @@ init_logger_from_env();
|
||||
|
||||
In this case the following environment variables are used:
|
||||
|
||||
- `ESP_LOGLEVEL` sets the log level, use values like `trace`, `info` etc.
|
||||
- `ESP_LOGTARGETS` if set you should provide the crate names of crates (optionally with a path e.g. `esp_wifi::compat::common`) which should get logged, separated by `,` and no additional whitespace between
|
||||
- `ESP_LOG` log messages you want to show, similar to `RUST_LOG`. RegEx is not supported. e.g. `warn,test::foo=info,test::foo::bar=debug`
|
||||
|
||||
If this simple logger implementation isn't sufficient for your needs, you can implement your own logger on top of `esp-println`. See [Implementing a Logger section log documentaion]
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
use std::{env, path::Path};
|
||||
|
||||
use esp_build::assert_unique_used_features;
|
||||
|
||||
fn main() {
|
||||
@ -29,4 +31,157 @@ fn main() {
|
||||
"cargo:warning=The `colors` feature is only effective when using the `log` feature"
|
||||
);
|
||||
}
|
||||
|
||||
if std::env::var("ESP_LOGLEVEL").is_ok() || std::env::var("ESP_LOGFILTER").is_ok() {
|
||||
panic!("`ESP_LOGLEVEL` and `ESP_LOGFILTER` is not supported anymore. Please use `ESP_LOG` instead.");
|
||||
}
|
||||
|
||||
generate_filter_snippet();
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
println!("cargo:rustc-cfg=host_is_windows");
|
||||
|
||||
println!("cargo:rerun-if-env-changed=ESP_LOG");
|
||||
println!("cargo:rustc-check-cfg=cfg(host_is_windows)");
|
||||
}
|
||||
|
||||
fn generate_filter_snippet() {
|
||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||
let dest_path = Path::new(&out_dir).join("log_filter.rs");
|
||||
|
||||
let filter = env::var("ESP_LOG");
|
||||
let snippet = if let Ok(filter) = filter {
|
||||
let res = parse_spec(&filter);
|
||||
|
||||
if !res.errors.is_empty() {
|
||||
panic!("Error parsing `ESP_LOG`: {:?}", res.errors);
|
||||
} else {
|
||||
let max = res
|
||||
.directives
|
||||
.iter()
|
||||
.map(|v| v.level)
|
||||
.max()
|
||||
.unwrap_or(log::LevelFilter::Off);
|
||||
let max = match max {
|
||||
log::LevelFilter::Off => "Off",
|
||||
log::LevelFilter::Error => "Error",
|
||||
log::LevelFilter::Warn => "Warn",
|
||||
log::LevelFilter::Info => "Info",
|
||||
log::LevelFilter::Debug => "Debug",
|
||||
log::LevelFilter::Trace => "Trace",
|
||||
};
|
||||
|
||||
let mut snippet = String::new();
|
||||
|
||||
snippet.push_str(&format!(
|
||||
"pub(crate) const FILTER_MAX: log::LevelFilter = log::LevelFilter::{};",
|
||||
max
|
||||
));
|
||||
|
||||
snippet
|
||||
.push_str("pub(crate) fn is_enabled(level: log::Level, _target: &str) -> bool {");
|
||||
|
||||
for directive in res.directives {
|
||||
let level = match directive.level {
|
||||
log::LevelFilter::Off => "Off",
|
||||
log::LevelFilter::Error => "Error",
|
||||
log::LevelFilter::Warn => "Warn",
|
||||
log::LevelFilter::Info => "Info",
|
||||
log::LevelFilter::Debug => "Debug",
|
||||
log::LevelFilter::Trace => "Trace",
|
||||
};
|
||||
|
||||
if let Some(name) = directive.name {
|
||||
snippet.push_str(&format!(
|
||||
"if _target.starts_with(\"{}\") && level <= log::LevelFilter::{} {{ return true; }}",
|
||||
&name, level
|
||||
));
|
||||
} else {
|
||||
snippet.push_str(&format!(
|
||||
"if level <= log::LevelFilter::{} {{ return true; }}",
|
||||
level
|
||||
));
|
||||
}
|
||||
}
|
||||
snippet.push_str(" false");
|
||||
snippet.push('}');
|
||||
snippet
|
||||
}
|
||||
} else {
|
||||
"pub(crate) const FILTER_MAX: log::LevelFilter = log::LevelFilter::Off; pub(crate) fn is_enabled(_level: log::Level, _target: &str) -> bool { true }".to_string()
|
||||
};
|
||||
|
||||
std::fs::write(&dest_path, &snippet).unwrap();
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct ParseResult {
|
||||
pub(crate) directives: Vec<Directive>,
|
||||
pub(crate) errors: Vec<String>,
|
||||
}
|
||||
|
||||
impl ParseResult {
|
||||
fn add_directive(&mut self, directive: Directive) {
|
||||
self.directives.push(directive);
|
||||
}
|
||||
|
||||
fn add_error(&mut self, message: String) {
|
||||
self.errors.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Directive {
|
||||
pub(crate) name: Option<String>,
|
||||
pub(crate) level: log::LevelFilter,
|
||||
}
|
||||
|
||||
/// Parse a logging specification string (e.g:
|
||||
/// `crate1,crate2::mod3,crate3::x=error/foo`) and return a vector with log
|
||||
/// directives.
|
||||
fn parse_spec(spec: &str) -> ParseResult {
|
||||
let mut result = ParseResult::default();
|
||||
|
||||
let mut parts = spec.split('/');
|
||||
let mods = parts.next();
|
||||
|
||||
if let Some(m) = mods {
|
||||
for s in m.split(',').map(|ss| ss.trim()) {
|
||||
if s.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let mut parts = s.split('=');
|
||||
let (log_level, name) =
|
||||
match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
|
||||
(Some(part0), None, None) => {
|
||||
// if the single argument is a log-level string or number,
|
||||
// treat that as a global fallback
|
||||
match part0.parse() {
|
||||
Ok(num) => (num, None),
|
||||
Err(_) => (log::LevelFilter::max(), Some(part0)),
|
||||
}
|
||||
}
|
||||
(Some(part0), Some(""), None) => (log::LevelFilter::max(), Some(part0)),
|
||||
(Some(part0), Some(part1), None) => {
|
||||
if let Ok(num) = part1.parse() {
|
||||
(num, Some(part0))
|
||||
} else {
|
||||
result.add_error(format!("invalid logging spec '{part1}'"));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
result.add_error(format!("invalid logging spec '{s}'"));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
result.add_directive(Directive {
|
||||
name: name.map(|s| s.to_owned()),
|
||||
level: log_level,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
use core::str::FromStr;
|
||||
|
||||
use log::LevelFilter;
|
||||
|
||||
use super::println;
|
||||
|
||||
const LOG_TARGETS: Option<&'static str> = option_env!("ESP_LOGTARGETS");
|
||||
#[cfg(not(host_is_windows))]
|
||||
include!(concat!(env!("OUT_DIR"), "/log_filter.rs"));
|
||||
|
||||
#[cfg(host_is_windows)]
|
||||
include!(concat!(env!("OUT_DIR"), "\\log_filter.rs"));
|
||||
|
||||
/// Initialize the logger with the given maximum log level.
|
||||
///
|
||||
/// `ESP_LOG` environment variable will still be honored if set.
|
||||
pub fn init_logger(level: log::LevelFilter) {
|
||||
unsafe {
|
||||
log::set_logger_racy(&EspLogger).unwrap();
|
||||
@ -13,38 +16,28 @@ pub fn init_logger(level: log::LevelFilter) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize the logger from the `ESP_LOG` environment variable.
|
||||
pub fn init_logger_from_env() {
|
||||
unsafe {
|
||||
log::set_logger_racy(&EspLogger).unwrap();
|
||||
}
|
||||
|
||||
const LEVEL: Option<&'static str> = option_env!("ESP_LOGLEVEL");
|
||||
|
||||
if let Some(lvl) = LEVEL {
|
||||
let level = LevelFilter::from_str(lvl).unwrap_or_else(|_| LevelFilter::Off);
|
||||
unsafe { log::set_max_level_racy(level) };
|
||||
log::set_max_level_racy(FILTER_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
struct EspLogger;
|
||||
|
||||
impl log::Log for EspLogger {
|
||||
fn enabled(&self, _metadata: &log::Metadata) -> bool {
|
||||
true
|
||||
fn enabled(&self, metadata: &log::Metadata) -> bool {
|
||||
let level = metadata.level();
|
||||
let target = metadata.target();
|
||||
is_enabled(level, target)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
fn log(&self, record: &log::Record) {
|
||||
// check enabled log targets if any
|
||||
if let Some(targets) = LOG_TARGETS {
|
||||
if targets
|
||||
.split(",")
|
||||
.find(|v| record.target().starts_with(v))
|
||||
.is_none()
|
||||
{
|
||||
if !self.enabled(&record.metadata()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const RESET: &str = "\u{001B}[0m";
|
||||
const RED: &str = "\u{001B}[31m";
|
||||
|
||||
@ -27,7 +27,7 @@ rustflags = [
|
||||
]
|
||||
|
||||
[env]
|
||||
ESP_LOGLEVEL = "info"
|
||||
ESP_LOG = "info"
|
||||
SSID = "SSID"
|
||||
PASSWORD = "PASSWORD"
|
||||
STATIC_IP = "1.1.1.1 "
|
||||
|
||||
Loading…
Reference in New Issue
Block a user