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}