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
20static IS_INIT: AtomicBool = AtomicBool::new(false);
24
25#[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 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
68pub 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#[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#[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#[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#[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#[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#[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#[cfg(r2r__rosgraph_msgs__msg__Clock)]
148#[macro_export]
149macro_rules! assert_compiled_with_use_sim_time_support {
150 () => {};
151}
152
153#[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}