defmt
defmt copied to clipboard
Compatibility for `log` logging macros?
While defmt is shaping up great for embedded logging, the nice thing about the normal log
macros is that they can be used in code that's used both in embedded and non-embedded contexts, such as:
-
Nontrivial libraries like
smoltcp
that are used in both contexts, where high-bandwidth logging is desirable in both cases. -
Parts of a firmware that are used non-embedded for testing and simulation purposes. It can be quite time saving to extract the hardware independent parts into a library crate, where they can be tested on normal CI infrastructure, and used to simulate the firmware's behavior.
In both cases, using defmt
would make this cumbersome, needing to make the logging conditional somehow.
I'm opening this issue for a discussion if it is possible to provide, as a part of defmt
, a shim that would keep logging usable for both contexts, with acceptable restrictions. The first thing coming to mind is a macro that makes a transformation like this:
debug!("{:u16} and {:str}", a, b);
=>
#[cfg(not(feature = "defmt-to-log"))]
defmt::debug!("{:u16} and {:str}", a, b);
#[cfg(feature = "defmt-to-log")]
log::debug!("{} and {}", a, b);
i.e. the format string is rewritten for log
and the two versions emitted side by side. Of course this can't expect to deliver the same output for all cases (bitfields come to mind), but IMO a best effort would make life much easier for the overwhelming majority of cases.
I believe we now handle the common cases with https://github.com/knurling-rs/defmt/issues/270. Whether we want to support the entire core::fmt
grammar is a different question, but this should already help a lot when trying to use both log
and defmt
, or when migrating.
It’d be great to have the user doc indicate any existing compatibility with the log crate, and perhaps an example. Compatibility was my first question. Thanks.
I'm new to embedded programming (trying out an stm32f10 nucleo board). probe-run
seems like a great idea, and it appeared defmt
goes hand-in-hand.
However I stumbled straight away on that defmt
has no support for the log
crate. I tried using the equivalent log macros like defmt::info!()
, but they are different in that they don't support all formatting options I'm used to (I have structs implementing a mix of Display
and Debug
) and get errors like unknown display hint: ".02"
.
I tried working around the problem by implement the glue myself:
use log::{Level, Log, Metadata, Record};
static DEFMT_LOGGER: DefmtLogger = DefmtLogger;
struct DefmtLogger;
impl Log for DefmtLogger {
fn enabled(&self, _metadata: &Metadata) -> bool {
true
}
fn log(&self, record: &Record) {
match record.level() {
Level::Error => defmt::error!("{}", record.args().as_str()),
Level::Warn => defmt::warn!("{}", record.args().as_str()),
Level::Info => defmt::info!("{}", record.args().as_str()),
Level::Debug => defmt::debug!("{}", record.args().as_str()),
Level::Trace => defmt::trace!("{}", record.args().as_str()),
}
}
fn flush(&self) {
defmt::flush();
}
}
fn init_log() {
log::set_logger(&DEFMT_LOGGER).unwrap();
}
But I guess there's something missing in my understanding, cause this doesn't seem to work.
Hi @algesten, It is great to see you tapping your toe into embedded development!
You are right that defmt
doesn't support all the display hints which are available in the rust std-library. We are not using the same formatting machinery, since this would be too expensive for most microcontrollers. defmt
is build around the trait defmt::Format
, which is implemented for most primitives and many core
-library types.
Please have a look into our user documentation at https://defmt.ferrous-systems.com/ for a overview of what defmt
is and how it can be used and ask more questions if you come across some.
Greetings 👋🏾
Hi @Urhengulas! Thanks for the kind words!
I understand the motivation, and after working with defmt for a day, nothing was particularly confusing. Thanks!
Would you be open for me making a PR to README.md that explains these things for beginners like me? Far down the page :)
Hi @Urhengulas! Thanks for the kind words!
I understand the motivation, and after working with defmt for a day, nothing was particularly confusing. Thanks!
That is good to hear!
Would you be open for me making a PR to README.md that explains these things for beginners like me? Far down the page :)
Yes, definitely! Either to the Readme or to the book (https://defmt.ferrous-systems.com).