r2r/
utils.rs

1use r2r_rcl::*;
2use std::{
3    ffi::CString,
4    sync::{
5        atomic::{AtomicBool, Ordering},
6        Mutex, MutexGuard,
7    },
8};
9
10use lazy_static::lazy_static;
11
12lazy_static! {
13    static ref LOG_GUARD: Mutex<()> = Mutex::new(());
14}
15
16pub(crate) fn log_guard() -> MutexGuard<'static, ()> {
17    LOG_GUARD.lock().unwrap()
18}
19
20// for some hidden reason g_rcutils_logging_initialized
21// is not found on windows even when rcutils.lib is linked
22// as a work around using onwned is_init
23static IS_INIT: AtomicBool = AtomicBool::new(false);
24
25/// Don't call this directly, use the logging macros instead.
26#[doc(hidden)]
27pub fn log(msg: &str, logger_name: &str, file: &str, line: u32, severity: LogSeverity) {
28    let _guard = log_guard();
29    let is_init = if cfg!(target_os = "windows") {
30        IS_INIT.load(Ordering::Relaxed)
31    } else {
32        unsafe { g_rcutils_logging_initialized }
33    };
34    if !is_init {
35        if cfg!(target_os = "windows") {
36            IS_INIT.store(true, Ordering::Relaxed);
37        }
38        let ret = unsafe { rcutils_logging_initialize() };
39        if ret != RCL_RET_OK as i32 {
40            log::error!("could not create logging system (Err: {})", ret);
41            return;
42        }
43    }
44    // currently not possible to get function name in rust.
45    // see https://github.com/rust-lang/rfcs/pull/2818
46    let function = CString::new("").unwrap();
47    let file = CString::new(file).unwrap();
48    let location = rcutils_log_location_t {
49        function_name: function.as_ptr(),
50        file_name: file.as_ptr(),
51        line_number: line as usize,
52    };
53    let format = CString::new("%s").unwrap();
54    let logger_name = CString::new(logger_name).unwrap();
55    let message = CString::new(msg).unwrap();
56    let severity = severity.to_native();
57    unsafe {
58        rcutils_log(
59            &location,
60            severity as i32,
61            logger_name.as_ptr(),
62            format.as_ptr(),
63            message.as_ptr(),
64        );
65    }
66}
67
68/// Logging severity
69pub enum LogSeverity {
70    Unset,
71    Debug,
72    Info,
73    Warn,
74    Error,
75    Fatal,
76}
77
78impl LogSeverity {
79    fn to_native(&self) -> RCUTILS_LOG_SEVERITY {
80        use RCUTILS_LOG_SEVERITY::*;
81        match self {
82            LogSeverity::Unset => RCUTILS_LOG_SEVERITY_UNSET,
83            LogSeverity::Debug => RCUTILS_LOG_SEVERITY_DEBUG,
84            LogSeverity::Info => RCUTILS_LOG_SEVERITY_INFO,
85            LogSeverity::Warn => RCUTILS_LOG_SEVERITY_WARN,
86            LogSeverity::Error => RCUTILS_LOG_SEVERITY_ERROR,
87            LogSeverity::Fatal => RCUTILS_LOG_SEVERITY_FATAL,
88        }
89    }
90}
91
92// A helper macro to log the message.
93#[doc(hidden)]
94#[macro_export]
95macro_rules! __impl_log {
96    ($logger_name:expr, $msg:expr, $file:expr, $line:expr, $severity:expr) => {{
97        $crate::log(&std::fmt::format($msg), $logger_name, $file, $line, $severity);
98    }};
99}
100
101/// Debug log message.
102#[macro_export]
103macro_rules! log_debug {
104    ($logger_name:expr, $($args:tt)*) => {{
105        $crate::__impl_log!($logger_name, format_args!($($args)*),
106                            file!(), line!(), $crate::LogSeverity::Debug)
107    }}
108}
109
110/// Info log message.
111#[macro_export]
112macro_rules! log_info {
113    ($logger_name:expr, $($args:tt)*) => {{
114        $crate::__impl_log!($logger_name, format_args!($($args)*),
115                            file!(), line!(), $crate::LogSeverity::Info)
116    }}
117}
118
119/// Warning log message.
120#[macro_export]
121macro_rules! log_warn {
122    ($logger_name:expr, $($args:tt)*) => {{
123        $crate::__impl_log!($logger_name, format_args!($($args)*),
124                            file!(), line!(), $crate::LogSeverity::Warn)
125    }}
126}
127
128/// Error log message.
129#[macro_export]
130macro_rules! log_error {
131    ($logger_name:expr, $($args:tt)*) => {{
132        $crate::__impl_log!($logger_name, format_args!($($args)*),
133                            file!(), line!(), $crate::LogSeverity::Error)
134    }}
135}
136
137/// Fatal log message.
138#[macro_export]
139macro_rules! log_fatal {
140    ($logger_name:expr, $($args:tt)*) => {{
141        $crate::__impl_log!($logger_name, format_args!($($args)*),
142                            file!(), line!(), $crate::LogSeverity::Fatal)
143    }}
144}
145
146/// Causes compile time error if `use_sim_time` is unsupported.
147#[cfg(r2r__rosgraph_msgs__msg__Clock)]
148#[macro_export]
149macro_rules! assert_compiled_with_use_sim_time_support {
150    () => {};
151}
152
153/// Causes compile time error if `use_sim_time` is unsupported.
154#[cfg(not(r2r__rosgraph_msgs__msg__Clock))]
155#[macro_export]
156macro_rules! assert_compiled_with_use_sim_time_support {
157    () => {
158        compile_error!("assert_compiled_with_use_sim_time_support failed: 'rosgraph_msgs' dependency is missing!");
159    };
160}
161
162#[test]
163fn test_log() {
164    log_debug!("log_test", "debug msg");
165    log_info!("log_test", "info msg");
166    log_warn!("log_test", "warn msg");
167    log_error!("log_test", "error msg");
168    log_fatal!("log_test", "fatal msg");
169}