rtapi_logger/lib.rs
1//! `rtapi-logger` is a logging driver for the [`log`](https://docs.rs/log) ecosystem.
2//!
3//! Other loggers which don't use the RTAPI logging machinery provided by LinuxCNC are relatively
4//! slow and can unnecessarily block realtime tasks. `rtapi-logger` hooks into LinuxCNC's logging
5//! machinery to prevent these problems, whilst also allowing the use of the convenient macros
6//! provided by [`log`].
7//!
8//! Please note this crate is still somewhat experimental. For example, currently all messages are
9//! logged at the `ERR` level provided by LinuxCNC.
10
11use linuxcnc_hal_sys::{rtapi_get_msg_level, rtapi_print_msg};
12use log::{Level, Metadata, Record};
13use std::ffi::CString;
14
15use log::{LevelFilter, SetLoggerError};
16
17/// Log level.
18///
19/// Defined in the LinuxCNC source as `msg_level_t`.
20///
21/// Note that this currently does nothing; all messages are logged at `ERR` level.
22#[derive(Debug, Copy, Clone)]
23enum RtapiLogLevel {
24 #[allow(unused)]
25 None = 0,
26 Err = 1,
27 Warn = 2,
28 Info = 3,
29 Dbg = 4,
30 All = 5,
31}
32
33impl From<Level> for RtapiLogLevel {
34 fn from(other: Level) -> Self {
35 match other {
36 Level::Error => Self::Err,
37 Level::Warn => Self::Warn,
38 Level::Info => Self::Info,
39 Level::Debug => Self::Dbg,
40 Level::Trace => Self::All,
41 }
42 }
43}
44
45static LOGGER: RtapiLogger = RtapiLogger;
46
47pub fn init() -> Result<(), SetLoggerError> {
48 let _rtapi_level = unsafe { rtapi_get_msg_level() };
49
50 // log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Info))
51 // Log everything by default
52 log::set_logger(&LOGGER).map(|()| log::set_max_level(LevelFilter::Trace))
53}
54
55pub struct RtapiLogger;
56
57impl log::Log for RtapiLogger {
58 // FIXME: This should not just return true - performance will take a hit. LinuxCNC's logging
59 // system does the filtering, so that works at least.
60 fn enabled(&self, _metadata: &Metadata) -> bool {
61 // metadata.level() <= Level::Info
62 true
63 }
64
65 fn log(&self, record: &Record) {
66 if self.enabled(record.metadata()) {
67 let out = format!("{}\n", record.args());
68
69 // FIXME: LinuxCNC seems to always use `Err` level regardless of DEBUG config value.
70 // let level: RtapiLogLevel = record.level().into();
71 let level = RtapiLogLevel::Err;
72
73 if let Ok(f) = CString::new(out) {
74 unsafe { rtapi_print_msg(level as u32, f.as_ptr()) };
75 } else {
76 let fail = CString::new("failed to build log message string").unwrap();
77
78 unsafe { rtapi_print_msg(level as u32, fail.as_ptr()) }
79 }
80 }
81 }
82
83 fn flush(&self) {}
84}