Skip to main content

mabi_core/logging/
macros.rs

1//! Logging and tracing macros.
2//!
3//! This module provides convenient macros for structured logging and tracing.
4
5/// Create a span for tracing protocol requests.
6///
7/// This macro creates a structured span with standard fields for request tracing.
8///
9/// # Example
10///
11/// ```rust,ignore
12/// use mabi_core::trace_request;
13///
14/// async fn handle_request() {
15///     let _span = trace_request!("modbus", "read_registers");
16///     // ... request handling
17/// }
18/// ```
19#[macro_export]
20macro_rules! trace_request {
21    ($protocol:expr, $operation:expr) => {
22        tracing::info_span!(
23            "request",
24            protocol = $protocol,
25            operation = $operation,
26            request_id = %uuid::Uuid::new_v4(),
27        )
28    };
29    ($protocol:expr, $operation:expr, $($field:tt)*) => {
30        tracing::info_span!(
31            "request",
32            protocol = $protocol,
33            operation = $operation,
34            request_id = %uuid::Uuid::new_v4(),
35            $($field)*
36        )
37    };
38}
39
40/// Create a span for tracing device operations.
41///
42/// # Example
43///
44/// ```rust,ignore
45/// use mabi_core::trace_device;
46///
47/// async fn device_tick(device_id: &str) {
48///     let _span = trace_device!(device_id, "tick");
49///     // ... device processing
50/// }
51/// ```
52#[macro_export]
53macro_rules! trace_device {
54    ($device_id:expr, $operation:expr) => {
55        tracing::debug_span!(
56            "device",
57            device_id = $device_id,
58            operation = $operation,
59        )
60    };
61    ($device_id:expr, $operation:expr, $($field:tt)*) => {
62        tracing::debug_span!(
63            "device",
64            device_id = $device_id,
65            operation = $operation,
66            $($field)*
67        )
68    };
69}
70
71/// Log a successful operation with timing.
72///
73/// # Example
74///
75/// ```rust,ignore
76/// use mabi_core::trace_success;
77/// use std::time::Instant;
78///
79/// let start = Instant::now();
80/// // ... operation
81/// trace_success!("read", start);
82/// ```
83#[macro_export]
84macro_rules! trace_success {
85    ($operation:expr, $start:expr) => {
86        tracing::info!(
87            operation = $operation,
88            duration_us = $start.elapsed().as_micros() as u64,
89            "Operation completed"
90        );
91    };
92    ($operation:expr, $start:expr, $($field:tt)*) => {
93        tracing::info!(
94            operation = $operation,
95            duration_us = $start.elapsed().as_micros() as u64,
96            $($field)*,
97            "Operation completed"
98        );
99    };
100}
101
102/// Log a failed operation with error details.
103///
104/// # Example
105///
106/// ```rust,ignore
107/// use mabi_core::trace_error;
108///
109/// match result {
110///     Ok(_) => {},
111///     Err(e) => trace_error!("read", e),
112/// }
113/// ```
114#[macro_export]
115macro_rules! trace_error {
116    ($operation:expr, $error:expr) => {
117        tracing::error!(
118            operation = $operation,
119            error = %$error,
120            "Operation failed"
121        );
122    };
123    ($operation:expr, $error:expr, $($field:tt)*) => {
124        tracing::error!(
125            operation = $operation,
126            error = %$error,
127            $($field)*,
128            "Operation failed"
129        );
130    };
131}
132
133/// Create a span for protocol message handling.
134///
135/// # Example
136///
137/// ```rust,ignore
138/// use mabi_core::trace_message;
139///
140/// let _span = trace_message!("modbus", "request", unit_id = 1);
141/// ```
142#[macro_export]
143macro_rules! trace_message {
144    ($protocol:expr, $direction:expr) => {
145        tracing::debug_span!(
146            "message",
147            protocol = $protocol,
148            direction = $direction,
149        )
150    };
151    ($protocol:expr, $direction:expr, $($field:tt)*) => {
152        tracing::debug_span!(
153            "message",
154            protocol = $protocol,
155            direction = $direction,
156            $($field)*
157        )
158    };
159}
160
161/// Log a connection event.
162///
163/// # Example
164///
165/// ```rust,ignore
166/// use mabi_core::trace_connection;
167///
168/// trace_connection!("modbus", "connected", peer = %addr);
169/// ```
170#[macro_export]
171macro_rules! trace_connection {
172    ($protocol:expr, $event:expr) => {
173        tracing::info!(
174            protocol = $protocol,
175            event = $event,
176            "Connection event"
177        );
178    };
179    ($protocol:expr, $event:expr, $($field:tt)*) => {
180        tracing::info!(
181            protocol = $protocol,
182            event = $event,
183            $($field)*,
184            "Connection event"
185        );
186    };
187}
188
189/// Log a state change with before/after values.
190///
191/// # Example
192///
193/// ```rust,ignore
194/// use mabi_core::trace_state_change;
195///
196/// trace_state_change!("engine", "stopped", "running");
197/// ```
198#[macro_export]
199macro_rules! trace_state_change {
200    ($component:expr, $from:expr, $to:expr) => {
201        tracing::info!(
202            component = $component,
203            from_state = $from,
204            to_state = $to,
205            "State changed"
206        );
207    };
208    ($component:expr, $from:expr, $to:expr, $($field:tt)*) => {
209        tracing::info!(
210            component = $component,
211            from_state = $from,
212            to_state = $to,
213            $($field)*,
214            "State changed"
215        );
216    };
217}
218
219/// Log a metric observation.
220///
221/// # Example
222///
223/// ```rust,ignore
224/// use mabi_core::trace_metric;
225///
226/// trace_metric!("request_duration_ms", 42.5, protocol = "modbus");
227/// ```
228#[macro_export]
229macro_rules! trace_metric {
230    ($name:expr, $value:expr) => {
231        tracing::debug!(
232            metric_name = $name,
233            metric_value = $value,
234            "Metric observation"
235        );
236    };
237    ($name:expr, $value:expr, $($field:tt)*) => {
238        tracing::debug!(
239            metric_name = $name,
240            metric_value = $value,
241            $($field)*,
242            "Metric observation"
243        );
244    };
245}
246
247/// Create a span for engine tick processing.
248///
249/// # Example
250///
251/// ```rust,ignore
252/// use mabi_core::trace_tick;
253///
254/// let _span = trace_tick!(42, device_count = 100);
255/// ```
256#[macro_export]
257macro_rules! trace_tick {
258    ($tick_num:expr) => {
259        tracing::trace_span!(
260            "tick",
261            tick = $tick_num,
262        )
263    };
264    ($tick_num:expr, $($field:tt)*) => {
265        tracing::trace_span!(
266            "tick",
267            tick = $tick_num,
268            $($field)*
269        )
270    };
271}
272
273/// Log entering a critical section or important function.
274///
275/// # Example
276///
277/// ```rust,ignore
278/// use mabi_core::trace_enter;
279///
280/// fn process_batch() {
281///     trace_enter!("process_batch", batch_size = 100);
282///     // ...
283/// }
284/// ```
285#[macro_export]
286macro_rules! trace_enter {
287    ($name:expr) => {
288        tracing::debug!(function = $name, "Entering");
289    };
290    ($name:expr, $($field:tt)*) => {
291        tracing::debug!(function = $name, $($field)*, "Entering");
292    };
293}
294
295/// Log exiting a critical section or important function.
296///
297/// # Example
298///
299/// ```rust,ignore
300/// use mabi_core::trace_exit;
301///
302/// fn process_batch() {
303///     // ...
304///     trace_exit!("process_batch", processed = 100);
305/// }
306/// ```
307#[macro_export]
308macro_rules! trace_exit {
309    ($name:expr) => {
310        tracing::debug!(function = $name, "Exiting");
311    };
312    ($name:expr, $($field:tt)*) => {
313        tracing::debug!(function = $name, $($field)*, "Exiting");
314    };
315}
316
317#[cfg(test)]
318mod tests {
319    // Macro tests would require initializing the tracing subscriber
320    // which can only be done once per process.
321    // These tests verify that the macros compile correctly.
322
323    #[test]
324    fn test_macros_compile() {
325        // This test just verifies the macros are syntactically correct
326        // by checking they can be expanded without errors
327    }
328}