Skip to content

Commit 3d91c8d

Browse files
committed
Add primitive printk-based logging
Support the `log` crate's log macros, using Zephyr's printk mechanism. There is no filter, or deferral of messages, and it pulls in both Rust and Zephyr's string formatting, but does allow logging to work directly. This is intended as a stopgap until better logging support comes in, but is also useful in its own right for builds where Zephyr logging is disabled. Signed-off-by: David Brown <[email protected]>
1 parent 37c77e2 commit 3d91c8d

File tree

4 files changed

+98
-0
lines changed

4 files changed

+98
-0
lines changed

zephyr/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Functionality for Rust-based applications that run on Zephyr.
1111

1212
[dependencies]
1313
zephyr-sys = { version = "3.7.0", path = "../zephyr-sys" }
14+
log = "0.4.22"
1415

1516
# Although paste is brought in, it is a compile-time macro, and is not linked into the application.
1617
paste = "1.0"

zephyr/src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ fn panic(info :&PanicInfo) -> ! {
6666
}
6767
}
6868

69+
#[cfg(CONFIG_PRINTK)]
70+
pub fn set_logger() {
71+
printk::set_printk_logger();
72+
}
73+
6974
/// Re-export of zephyr-sys as `zephyr::raw`.
7075
pub mod raw {
7176
pub use zephyr_sys::*;
@@ -86,3 +91,14 @@ pub mod _export {
8691
// If allocation has been requested, provide the allocator.
8792
#[cfg(CONFIG_RUST_ALLOC)]
8893
pub mod alloc_impl;
94+
95+
// If we have allocation, we can also support logging.
96+
#[cfg(CONFIG_RUST_ALLOC)]
97+
pub mod log {
98+
#[cfg(CONFIG_LOG)]
99+
compile_error!("Rust with CONFIG_LOG is not yet supported");
100+
101+
mod log_printk;
102+
103+
pub use log_printk::*;
104+
}

zephyr/src/log/log_printk.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//! A very simplistic logger that allocates and uses printk.
2+
//!
3+
//! This is just a stop gap so that users of Rust can have some simple messages. This provides a
4+
//! `println` macro that works similar to the one in std.
5+
//!
6+
//! This module allocates at least twice as much space as the final message, for the duration of the
7+
//! print call.
8+
//!
9+
//! An unfortunate caveat of this crate is that using it requires clients to have `extern crate
10+
//! alloc;` in each module that uses it.
11+
12+
extern crate alloc;
13+
14+
use alloc::ffi::CString;
15+
16+
pub use alloc::format;
17+
18+
// Printk, with a fixed C-string formatting argument, and one we've built here.
19+
extern "C" {
20+
fn printk(fmt: *const i8, ...);
21+
}
22+
23+
pub fn log_message(message: &str) {
24+
let raw = CString::new(message).expect("CString::new failed");
25+
unsafe {
26+
printk(c"%s\n".as_ptr(), raw.as_ptr());
27+
}
28+
}
29+
30+
// We assume the log message is accessible at $crate::log::log_message.
31+
#[macro_export]
32+
macro_rules! println {
33+
($($arg:tt)+) => {
34+
{
35+
let message = $crate::log::format!($($arg)+);
36+
$crate::log::log_message(&message);
37+
}
38+
};
39+
}

zephyr/src/printk.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use core::fmt::{
1212
write,
1313
};
1414

15+
use log::{LevelFilter, Log, Metadata, Record};
16+
1517
/// Print to Zephyr's console, without a newline.
1618
///
1719
/// This macro uses the same syntax as std's
@@ -46,6 +48,46 @@ macro_rules! printkln {
4648
}};
4749
}
4850

51+
/// A simple log handler built around printk.
52+
struct PrintkLogger;
53+
54+
impl Log for PrintkLogger {
55+
// Initially, everything is just available.
56+
fn enabled(&self, _metadata: &Metadata<'_>) -> bool {
57+
true
58+
}
59+
60+
// Just print out the information.
61+
fn log(&self, record: &Record<'_>) {
62+
printkln!("{}:{}: {}",
63+
record.level(),
64+
record.target(),
65+
record.args());
66+
}
67+
68+
// Nothing to do for flush.
69+
fn flush(&self) {
70+
}
71+
}
72+
73+
static PRINTK_LOGGER: PrintkLogger = PrintkLogger;
74+
75+
// The cfg matches what is in the log crate, which doesn't use portable atomic, and assumes the
76+
// racy init when not the case.
77+
#[cfg(target_has_atomic = "ptr")]
78+
pub fn set_printk_logger() {
79+
log::set_logger(&PRINTK_LOGGER).unwrap();
80+
log::set_max_level(LevelFilter::Info);
81+
}
82+
83+
#[cfg(not(target_has_atomic = "ptr"))]
84+
pub fn set_printk_logger() {
85+
unsafe {
86+
log::set_logger_racy(&PRINTK_LOGGER).unwrap();
87+
log::set_max_level_racy(LevelFilter::Info);
88+
}
89+
}
90+
4991
// This could readily be optimized for the configuration where we don't have userspace, as well as
5092
// when we do, and are not running in userspace. This initial implementation will always use a
5193
// string buffer, as it doesn't depend on static symbols in print.c.

0 commit comments

Comments
 (0)