Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compatibility for log logging macros? #149

Open
birkenfeld opened this issue Aug 29, 2020 · 6 comments
Open

Compatibility for log logging macros? #149

birkenfeld opened this issue Aug 29, 2020 · 6 comments
Labels
difficulty: hard Fairly difficult to solve priority: low Low priority for the Knurling team status: needs design This feature needs design work to move forward type: enhancement Enhancement or feature request

Comments

@birkenfeld
Copy link
Contributor

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.

@birkenfeld birkenfeld changed the title Compatibility with for log logging macros? Compatibility for log logging macros? Aug 29, 2020
@jonas-schievink jonas-schievink added the type: enhancement Enhancement or feature request label Sep 1, 2020
@jonas-schievink jonas-schievink added difficulty: hard Fairly difficult to solve priority: low Low priority for the Knurling team status: needs design This feature needs design work to move forward labels Nov 17, 2020
@jonas-schievink
Copy link
Contributor

I believe we now handle the common cases with #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.

@huntc
Copy link

huntc commented Apr 5, 2021

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.

@algesten
Copy link

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.

@Urhengulas
Copy link
Member

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 👋🏾

@algesten
Copy link

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 :)

@Urhengulas
Copy link
Member

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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
difficulty: hard Fairly difficult to solve priority: low Low priority for the Knurling team status: needs design This feature needs design work to move forward type: enhancement Enhancement or feature request
Projects
None yet
Development

No branches or pull requests

5 participants