#elf #symtab

no-std stlog

Ultra lightweight logging framework for resource constrained devices

4 releases (2 breaking)

0.3.3 Nov 27, 2019
0.3.2 Sep 23, 2018
0.2.0 Jul 6, 2017
0.1.0 Jun 4, 2017

#276 in Debugging

MIT/Apache

19KB
282 lines

crates.io crates.io

stlog

Ultra lightweight logging framework for resource constrained devices

Documentation

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.


lib.rs:

Ultra lightweight logging framework for resource constrained devices

stlog running on a Cortex-M microcontroller

See stlog in action!

Features

  • O(1) execution time. Logging a message of arbitrary size is done in a constant number of instructions.

  • O(0) memory usage. The messages are NOT stored in the target device memory (.rodata).

  • Supports different logging levels: error, warning, info, debug and trace, in decreasing level of severity. By default, the dev profile logs debug, and more severe, messages and the release profile logs info, and more severe, messages, but this can changed using the Cargo features of this crate.

  • Provides a global logging mode

Non-features

  • printf style or any other kind of formatting

MSRV

This crate is guaranteed to compile on stable Rust 1.31 and up. It might compile on older versions but that may change in any new patch release.

Known limitations

  • The current implementation only supports 256 different log strings. This restriction may be lifted in the future.

  • The string should not contain the character @. Any text that follows this character will be discarded.

  • The exact same string can't be used in two or more macro invocations. Enabling the spanned Cargo feature removes this limitation.

use stlog::{error, info};

fn foo() {
    info!("Hello!");
}

fn good() {
    foo();
    foo();
}

fn bad() {
    info!("Hey!");
    info!("Hey!"); //~ ERROR symbol `Hey!` is already defined
}

fn also_bad() {
    info!("Bye!");
    error!("Bye!"); //~ ERROR symbol `Bye!` is already defined
}

Requirements

The target application must be linked using the stlog.x linker script provided by this crate. The easiest way to do this is to append the -C link-arg to the other rustc flags using a Cargo configuration file (.cargo/config).

[target.thumbv7m-none-eabi]
rustflags = [
    "-C", "link-arg=-Tstlog.x",
    # ..
]

To decode the logs on the host you'll need version v0.2.x of the stcat tool.

Examples

Local logger

  • Device side
use stlog::{info, warn, Log};

struct Logger {
    // ..
#   _0: (),
}

impl Log for Logger {
    // ..
#   type Error = ();
#
#   fn log(&mut self, _: u8) -> Result<(), ()> {
#       Ok(())
#   }
}

fn main() {
    let mut logger = Logger {
        // ..
#       _0: (),
    };

    info!(logger, "Hello, world!");
    warn!(logger, "The quick brown fox jumps over the lazy dog");
}
  • Host side

Assuming that the device is logging through the /dev/ttyUSB0 interface.

$ flash-and-run /path/to/device/binary

$ cat /dev/ttyUSB0 | stcat -e /path/to/device/binary
Sept 22 13:00:00.000 INFO Hello, world!
Sept 22 13:00:00.001 WARN The quick brown fox jumps over the lazy dog

Global logger

If the first argument is omitted from the logging macros then logging will be done through the global logger. The global logger must be selected using the global_logger attribute in the top crate.

use stlog::{info, GlobalLog};

struct Logger;

impl GlobalLog for Logger { .. }

#[global_logger]
static LOGGER: Logger = Logger;

fn main() {
    info!("Hello");
}

#[interrupt]
fn SomeInterrupt() {
    info!("World");
}

Cargo features

spanned

Enabling this feature adds variants of the macros, that include span information, under the spanned module. For example, spanned::info!("Hello") will log the string "Hello, loc: src/main.rs:12", where src/main.rs:12 is the location of the macro invocation.

This feature depends on unstable proc_macro features and requires a nightly compiler.

[release-]max-level-{off,error,warning,info,debug,trace}

These features can be used to enable / disable logging levels at compile time.

  • max-level-off will disable all levels
  • max-level-error enables the error level and disables everything else
  • max-level-warning enables the error and warning levels and disables everything else
  • max-level-info enables the error, warning and info levels and disables everything else
  • max-level-debug enables everything but the trace level
  • max-level-trace enables all levels

The release- prefixed features affect the release profile, while the other features only affect the dev profile.

If none of these features are enabled the release profile enables the error, warning and info levels, and the dev profile additionally enables the debug level.

Troubleshooting

Didn't pass -Tstlog.x to the linker

Symptom: you'll get an error when linking the target application or when calling stcat.

$ cargo build
error: linking with `rust-lld` failed: exit code: 1
  |
  = note: "rust-lld" (..)
  = note: rust-lld: error: no memory region specified for section '.stlog.info'
          rust-lld: error: no memory region specified for section '.stlog.error'

$ stcat -e /path/to/binary logfile
error: symbol `__stlog_error_start__` not found

Pass -Tstlog.x to the linker as explained in the requirements section.

Didn't set a global_logger

Symptom: you'll get an error when linking the program

$ cargo build
error: linking with `rust-lld` failed: exit code: 1
  |
  = note: "rust-lld" (..)
  = note: rust-lld: error: undefined symbol: stlog::GLOBAL_LOGGER

Dependencies

~225–630KB
~15K SLoC