rtt_log/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(test), no_std)]
3
4pub use rtt_target;
5
6use once_cell::sync::OnceCell;
7use rtt_target::{rprintln, rtt_init_print};
8
9struct Logger {
10    level_filter: log::LevelFilter,
11}
12
13impl log::Log for Logger {
14    /// Returns if logger is enabled.
15    fn enabled(&self, metadata: &log::Metadata) -> bool {
16        metadata.level() <= self.level_filter
17    }
18
19    /// Log the record.
20    fn log(&self, record: &log::Record) {
21        if self.enabled(record.metadata()) {
22            rprintln!(
23                "{:<5} [{}] {}",
24                record.level(),
25                record.target(),
26                record.args()
27            );
28        }
29    }
30
31    /// Flush buffered records.
32    fn flush(&self) {
33        // Nothing to do here
34    }
35}
36
37static LOGGER: OnceCell<Logger> = OnceCell::new();
38
39/// Init the logger with maximum level (Trace).
40pub fn init() {
41    init_with_level(log::LevelFilter::Trace);
42}
43
44/// Init the logger with a specific level.
45pub fn init_with_level(level_filter: log::LevelFilter) {
46    // Logger was already initialized.
47    if LOGGER.get().is_some() {
48        return;
49    }
50    let logger = LOGGER.get_or_init(|| Logger { level_filter });
51    rtt_init_print!();
52
53    // Use racy init if the feature is enabled or the target doesn't support atomic pointers.
54    #[cfg(any(not(target_has_atomic = "ptr"), feature = "racy_init"))]
55    unsafe {
56        init_racy(logger);
57    }
58
59    // Use the default init otherwise.
60    #[cfg(all(target_has_atomic = "ptr", not(feature = "racy_init")))]
61    init_default(logger);
62}
63
64#[cfg(all(target_has_atomic = "ptr", not(feature = "racy_init")))]
65fn init_default(logger: &'static Logger) {
66    log::set_logger(logger).ok();
67    log::set_max_level(logger.level_filter);
68}
69
70// # Safety
71//
72// This function will call the unsafe functions [log::set_logger_racy] and
73// [log::set_max_level_racy] if either the feature `racy_init` is enabled or the target doesn't
74// support atomic pointers. The [once_cell::OnceCell] should ensure that this is only called
75// once.
76#[cfg(any(not(target_has_atomic = "ptr"), feature = "racy_init"))]
77unsafe fn init_racy(logger: &'static Logger) {
78    log::set_logger_racy(logger).ok();
79    log::set_max_level_racy(logger.level_filter);
80}