diff --git a/.vscode/settings.json b/.vscode/settings.json index 8b9059e..12c0d76 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,7 +2,9 @@ "editor.formatOnSave": true, "rust-analyzer.cargo.features": [ "esp32c3", - "jtag_serial" + "jtag_serial", + "log" ], "rust-analyzer.cargo.target": "riscv32imc-unknown-none-elf", + "rust-analyzer.showUnlinkedFileNotification": false, } \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 8a70865..f71afd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,10 +20,12 @@ log = { version = "0.4.17", optional = true } critical-section = { version = "1.1.1", optional = true } [features] -default = ["uart", "critical-section"] +default = ["uart", "critical-section", "colors"] crlf = [] +log = ["dep:log"] + # You must enable exactly 1 of the below features to support the correct chip: esp32 = [] esp32c2 = [] @@ -40,3 +42,6 @@ uart = [] jtag_serial = [] # C3, C6, H2, and S3 only! rtt = [] no-op = [] + +# logging sub-features +colors = [] diff --git a/README.md b/README.md index b0ef63e..7aa8195 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # esp-println -Provides `print!` and `println!` implementations for various Espressif devices. +Provides `print!`, `println!` and `dbg!` implementations for various Espressif devices. - Supports ESP32, ESP32-C2/C3/C6, ESP32-H2, ESP32-S2/S3, and ESP8266 - Dependency free (not even depending on `esp-hal`, one optional dependency is `log`, another is `critical-section`) @@ -8,7 +8,7 @@ Provides `print!` and `println!` implementations for various Espressif devices. - Supports RTT (lacking working RTT hosts besides _probe-rs_ for ESP32-C3) - `no-op` features turns printing into a no-op -## RTT on ESP32-C3 +## RTT on ESP32-C3 / ESP32-C6 The _cli_ utility should work for flashing and showing RTT logs on ESP32-C3 by using it's `run` command. You need to use the `direct-boot` feature of the HAL to flash via _probe-rs_. @@ -31,6 +31,25 @@ use esp_println::println; You can now `println!("Hello world")` as usual. +## Logging + +With the feature `log` activated you can initialize a simple logger like this +```rust +init_logger(log::LevelFilter::Info); +``` + +There is a default feature `colors` which enables colored log output. + +Additionally you can use +```rust +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 + +If this simple logger implementation isn't sufficient for your needs you can implement your own logger on top of `esp-println` - see https://docs.rs/log/0.4.17/log/#implementing-a-logger ## License diff --git a/src/logger.rs b/src/logger.rs index b30f7f0..394f45b 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -1,8 +1,28 @@ +use core::str::FromStr; + +use log::LevelFilter; + use super::println; +const LOG_TARGETS: Option<&'static str> = option_env!("ESP_LOGTARGETS"); + pub fn init_logger(level: log::LevelFilter) { unsafe { log::set_logger_racy(&EspLogger).unwrap(); + } + + log::set_max_level(level); +} + +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); log::set_max_level(level); } } @@ -14,8 +34,43 @@ impl log::Log for EspLogger { true } + #[allow(unused)] fn log(&self, record: &log::Record) { - println!("{} - {}", record.level(), record.args()); + // check enabled log targets if any + if let Some(targets) = LOG_TARGETS { + if targets + .split(",") + .find(|v| record.target().starts_with(v)) + .is_none() + { + return; + } + } + + const RESET: &str = "\u{001B}[0m"; + const RED: &str = "\u{001B}[31m"; + const GREEN: &str = "\u{001B}[32m"; + const YELLOW: &str = "\u{001B}[33m"; + const BLUE: &str = "\u{001B}[34m"; + const CYAN: &str = "\u{001B}[35m"; + + #[cfg(feature = "colors")] + let color = match record.level() { + log::Level::Error => RED, + log::Level::Warn => YELLOW, + log::Level::Info => GREEN, + log::Level::Debug => BLUE, + log::Level::Trace => CYAN, + }; + #[cfg(feature = "colors")] + let reset = RESET; + + #[cfg(not(feature = "colors"))] + let color = ""; + #[cfg(not(feature = "colors"))] + let reset = ""; + + println!("{}{} - {}{}", color, record.level(), record.args(), reset); } fn flush(&self) {}