veecle_telemetry/macros.rs
1//! Macros for structured logging and telemetry.
2//!
3//! This module provides convenient macros for creating spans, adding events, and logging
4//! messages with various severity levels.
5//! The macros provide a more ergonomic interface compared to the lower-level functions and handle attribute creation
6//! automatically.
7//!
8//! # Span Creation
9//!
10//! - `span!`: Creates a new span with optional attributes
11//! - `event!`: Adds an event to the current span
12//!
13//! # Logging Macros
14//!
15//! - `log!`: Generic logging macro that accepts a severity level
16//! - `trace!`: Logs trace-level messages (most verbose)
17//! - `debug!`: Logs debug-level messages
18//! - `info!`: Logs informational messages
19//! - `warn!`: Logs warning messages
20//! - `error!`: Logs error messages
21//! - `fatal!`: Logs fatal error messages
22//!
23//! # Attribute Handling
24//!
25//! - `attributes!`: Creates a slice of key-value attributes
26//! - `attribute!`: Creates a single key-value attribute
27//!
28//! All macros support flexible attribute syntax for adding contextual information.
29
30/// Creates a new span.
31///
32/// A span represents a unit of work or operation that has a beginning and end.
33/// It can contain attributes that provide additional context about the operation.
34///
35/// # Examples
36///
37/// ```rust
38/// use veecle_telemetry::span;
39///
40/// let span = span!("database_query");
41/// ```
42///
43/// ```rust
44/// use veecle_telemetry::span;
45///
46/// let user_id = 123;
47/// let table_name = "users";
48/// let span =
49/// span!("database_query", user_id, table = table_name, "operation" = "select");
50/// ```
51#[macro_export]
52macro_rules! span {
53 ($name:literal) => {
54 $crate::Span::new($name, &[])
55 };
56 ($name:literal, $($attributes:tt)+) => {
57 $crate::Span::new($name, $crate::attributes!($($attributes)+))
58 };
59}
60
61/// Creates a new root span.
62///
63/// See [span].
64///
65/// # Examples
66///
67/// ```rust
68/// use veecle_telemetry::root_span;
69///
70/// let span = root_span!("request");
71/// ```
72#[macro_export]
73macro_rules! root_span {
74 ($name:literal) => {
75 $crate::Span::root($name, $crate::id::SpanContext::generate(), &[])
76 };
77 ($name:literal, $($attributes:tt)+) => {
78 $crate::Span::root($name, $crate::id::SpanContext::generate(), $crate::attributes!($($attributes)+))
79 };
80}
81
82/// Adds an event to the current span.
83///
84/// Events are timestamped occurrences that happen during the execution of a span.
85/// They can include additional context through attributes.
86///
87/// # Examples
88///
89/// Add a simple event:
90/// ```rust
91/// use veecle_telemetry::event;
92///
93/// event!("cache_miss");
94/// ```
95///
96/// Add an event with attributes:
97/// ```rust
98/// use veecle_telemetry::event;
99///
100/// let key = "user:123";
101/// let cache_type = "redis";
102/// event!("cache_miss", key = key, cache_type = cache_type, "retry_count" = 3);
103/// ```
104#[macro_export]
105macro_rules! event {
106 ($name:literal) => {
107 $crate::CurrentSpan::add_event($name, &[])
108 };
109 ($name:literal, $($attributes:tt)+) => {
110 $crate::CurrentSpan::add_event($name, $crate::attributes!($($attributes)+))
111 };
112}
113
114/// Logs a message with the specified severity level.
115///
116/// This is the base logging macro that other severity-specific macros build upon.
117/// It allows you to specify the severity level and optional attributes.
118///
119/// # Examples
120///
121/// Log a simple message:
122/// ```rust
123/// use veecle_telemetry::log;
124/// use veecle_telemetry::protocol::Severity;
125///
126/// log!(Severity::Info, "Application started");
127/// ```
128///
129/// Log a message with attributes:
130/// ```rust
131/// use veecle_telemetry::log;
132/// use veecle_telemetry::protocol::Severity;
133///
134/// let port = 8080;
135/// let version = "1.0.0";
136/// log!(Severity::Info, "Server listening", port = port, version = version, "protocol" = "HTTP");
137/// ```
138#[macro_export]
139macro_rules! log {
140 ($severity:expr, $body:literal) => {
141 $crate::log::log($severity, $body, &[])
142 };
143
144 ($severity:expr, $body:literal, $($attributes:tt)+) => {
145 $crate::log::log($severity, $body, $crate::attributes!($($attributes)+))
146 };
147}
148
149/// Logs a trace-level message.
150///
151/// Trace messages are used for very detailed debugging information,
152/// typically only enabled during development or deep troubleshooting.
153///
154/// # Examples
155///
156/// Simple trace message:
157/// ```rust
158/// use veecle_telemetry::trace;
159///
160/// trace!("Entering function");
161/// ```
162///
163/// Trace message with context:
164/// ```rust
165/// use veecle_telemetry::trace;
166///
167/// let function_name = "process_request";
168/// let request_id = "req-123";
169/// trace!("Function entry", function = function_name, request_id = request_id);
170/// ```
171#[macro_export]
172macro_rules! trace {
173 ($body:literal) => {
174 $crate::log!($crate::protocol::Severity::Trace, $body);
175 };
176 ($body:literal, $($attribute:tt)+) => {
177 $crate::log!($crate::protocol::Severity::Trace, $body, $($attribute)+);
178 };
179}
180
181/// Logs a debug-level message.
182///
183/// Debug messages provide detailed information about the program's execution,
184/// useful for diagnosing issues during development and testing.
185///
186/// # Examples
187///
188/// Simple debug message:
189/// ```rust
190/// use veecle_telemetry::debug;
191///
192/// debug!("Processing user request");
193/// ```
194///
195/// Debug message with variables:
196/// ```rust
197/// use veecle_telemetry::debug;
198///
199/// let user_id = 456;
200/// let action = "login";
201/// debug!("User action processed", user_id = user_id, action = action, "success" = true);
202/// ```
203#[macro_export]
204macro_rules! debug {
205 ($body:literal) => {
206 $crate::log!($crate::protocol::Severity::Debug, $body);
207 };
208 ($body:literal, $($attribute:tt)+) => {
209 $crate::log!($crate::protocol::Severity::Debug, $body, $($attribute)+);
210 };
211}
212
213/// Logs an info-level message.
214///
215/// Info messages provide general information about the program's execution,
216/// suitable for normal operational logging.
217///
218/// # Examples
219///
220/// Simple info message:
221/// ```rust
222/// use veecle_telemetry::info;
223///
224/// info!("Service started successfully");
225/// ```
226///
227/// Info message with metadata:
228/// ```rust
229/// use veecle_telemetry::info;
230///
231/// let service_name = "web-server";
232/// let version = "2.1.0";
233/// info!(
234/// "Service initialization complete",
235/// service = service_name,
236/// version = version,
237/// "startup_time_ms" = 1250
238/// );
239/// ```
240#[macro_export]
241macro_rules! info {
242 ($body:literal) => {
243 $crate::log!($crate::protocol::Severity::Info, $body);
244 };
245 ($body:literal, $($attribute:tt)+) => {
246 $crate::log!($crate::protocol::Severity::Info, $body, $($attribute)+);
247 };
248}
249
250/// Logs a warning-level message.
251///
252/// Warning messages indicate potential issues or unusual conditions
253/// that don't prevent the program from continuing but should be noted.
254///
255/// # Examples
256///
257/// Simple warning message:
258/// ```rust
259/// use veecle_telemetry::warn;
260///
261/// warn!("Rate limit approaching");
262/// ```
263///
264/// Warning with context:
265/// ```rust
266/// use veecle_telemetry::warn;
267///
268/// let current_requests = 950;
269/// let limit = 1000;
270/// warn!(
271/// "High request rate detected",
272/// current_requests = current_requests,
273/// limit = limit,
274/// "utilization_percent" = 95
275/// );
276/// ```
277#[macro_export]
278macro_rules! warn {
279 ($body:literal) => {
280 $crate::log!($crate::protocol::Severity::Warn, $body);
281 };
282 ($body:literal, $($attribute:tt)+) => {
283 $crate::log!($crate::protocol::Severity::Warn, $body, $($attribute)+);
284 };
285}
286
287/// Logs an error-level message.
288///
289/// Error messages indicate serious problems that have occurred
290/// but allow the program to continue running.
291///
292/// # Examples
293///
294/// Simple error message:
295/// ```rust
296/// use veecle_telemetry::error;
297///
298/// error!("Database connection failed");
299/// ```
300///
301/// Error with details:
302/// ```rust
303/// use veecle_telemetry::error;
304///
305/// let db_host = "localhost:5432";
306/// let error_code = 1001;
307/// error!(
308/// "Database operation failed",
309/// host = db_host,
310/// error_code = error_code,
311/// "retry_attempted" = true
312/// );
313/// ```
314#[macro_export]
315macro_rules! error {
316 ($body:literal) => {
317 $crate::log!($crate::protocol::Severity::Error, $body);
318 };
319 ($body:literal, $($attribute:tt)+) => {
320 $crate::log!($crate::protocol::Severity::Error, $body, $($attribute)+);
321 };
322}
323
324/// Logs a fatal-level message.
325///
326/// Fatal messages indicate critical errors that will likely cause
327/// the program to terminate or become unusable.
328///
329/// # Examples
330///
331/// Simple fatal message:
332/// ```rust
333/// use veecle_telemetry::fatal;
334///
335/// fatal!("Critical system failure");
336/// ```
337///
338/// Fatal error with context:
339/// ```rust
340/// use veecle_telemetry::fatal;
341///
342/// let component = "memory_allocator";
343/// let error_type = "out_of_memory";
344/// fatal!(
345/// "System component failure",
346/// component = component,
347/// error_type = error_type,
348/// "available_memory_mb" = 0
349/// );
350/// ```
351#[macro_export]
352macro_rules! fatal {
353 ($body:literal) => {
354 $crate::log!($crate::protocol::Severity::Fatal, $body);
355 };
356 ($body:literal, $($attribute:tt)+) => {
357 $crate::log!($crate::protocol::Severity::Fatal, $body, $($attribute)+);
358 };
359}
360
361/// Constructs a slice of `KeyValue` attributes.
362///
363/// This macro is primarily used when manually constructing spans, such as root spans
364/// that don't have a convenience macro.
365///
366/// # Syntax
367///
368/// The macro supports several attribute formats:
369/// - `identifier = value` - Uses the identifier as the key name
370/// - `"literal" = value` - Uses the literal string as the key name
371/// - `identifier` - Uses the identifier as both key and value
372/// - `field.subfield` - Simple dot notation for field access
373///
374/// # Examples
375///
376/// Basic usage with mixed attribute types:
377/// ```rust
378/// use veecle_telemetry::attributes;
379///
380/// let user_id = 123;
381/// let service_name = "auth-service";
382/// let attrs = attributes!(user_id = user_id, "service" = service_name, "version" = "1.0.0");
383/// ```
384///
385/// Using identifiers as both key and value:
386/// ```rust
387/// use veecle_telemetry::attributes;
388///
389/// let database = "postgresql";
390/// let timeout = 30;
391/// let attrs = attributes!(
392/// database, // equivalent to database = database
393/// timeout = timeout,
394/// "connection_pool" = "primary"
395/// );
396/// ```
397///
398/// Root span construction with attributes:
399/// ```rust
400/// use veecle_telemetry::{Span, SpanContext, attributes};
401///
402/// let operation = "user_login";
403/// let user_id = 456;
404/// let span = Span::root(
405/// "authentication",
406/// SpanContext::generate(),
407/// attributes!(operation = operation, user_id = user_id, "security_level" = "high"),
408/// );
409/// ```
410///
411/// Empty attributes:
412/// ```rust
413/// use veecle_telemetry::attributes;
414/// use veecle_telemetry::value::KeyValue;
415///
416/// let attrs: &[KeyValue] = attributes!(); // Creates an empty slice
417/// ```
418#[macro_export]
419macro_rules! attributes {
420 // base case
421 (@ { $(,)* $($val:expr),* $(,)* }, $(,)*) => {
422 &[ $($val),* ]
423 };
424
425 // recursive
426 (@ { $(,)* $($out:expr),* }, $($key:ident).+, $($rest:tt)+) => {
427 $crate::attributes!(
428 @ { $($out),*, $crate::attribute!($($key).+) },
429 $($rest)*
430 )
431 };
432 (@ { $(,)* $($out:expr),* }, $($key:ident)+ = $value:expr, $($rest:tt)+) => {
433 $crate::attributes!(
434 @ { $($out),*, $crate::attribute!($($key).+ = $value) },
435 $($rest)*
436 )
437 };
438 (@ { $(,)* $($out:expr),* }, $key:literal = $value:expr, $($rest:tt)+) => {
439 $crate::attributes!(
440 @ { $($out),*, $crate::attribute!($key = $value) },
441 $($rest)*
442 )
443 };
444
445 (@ { $(,)* $($out:expr),* }, $($key:ident).+) => {
446 $crate::attributes!(
447 @ { $($out),*, $crate::attribute!($($key).+) },
448 )
449 };
450 (@ { $(,)* $($out:expr),* }, $($key:ident)+ = $value:expr) => {
451 $crate::attributes!(
452 @ { $($out),*, $crate::attribute!($($key).+ = $value) },
453 )
454 };
455 (@ { $(,)* $($out:expr),* }, $key:literal = $value:expr) => {
456 $crate::attributes!(
457 @ { $($out),*, $crate::attribute!($key = $value) },
458 )
459 };
460
461 // entry
462 ({ $($kvs:tt)+ }) => {
463 $crate::attributes!(@ { }, $($kvs)+)
464 };
465 ($($kvs:tt)+) => {
466 $crate::attributes!(@ { }, $($kvs)+)
467 };
468 ($(,)?) => {
469 &[]
470 };
471}
472
473/// Constructs a single attribute `KeyValue` pair.
474#[macro_export]
475macro_rules! attribute {
476 ($($key:ident)+ = $value:expr) => {
477 $crate::value::KeyValue::new(::core::stringify!($($key).+), $value)
478 };
479 ($key:literal = $value:expr) => {
480 $crate::value::KeyValue::new($key, $value)
481 };
482 ($($key:ident)+) => {
483 $crate::value::KeyValue::new(::core::stringify!($($key).+), $($key).+)
484 };
485}