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 $(, $($attributes:tt)*)?) => {
54 $crate::Span::new($name, $crate::attributes!($($($attributes)*)?))
55 };
56}
57
58/// Adds an event to the current span.
59///
60/// Events are timestamped occurrences that happen during the execution of a span.
61/// They can include additional context through attributes.
62///
63/// # Examples
64///
65/// Add a simple event:
66/// ```rust
67/// use veecle_telemetry::event;
68///
69/// event!("cache_miss");
70/// ```
71///
72/// Add an event with attributes:
73/// ```rust
74/// use veecle_telemetry::event;
75///
76/// let key = "user:123";
77/// let cache_type = "redis";
78/// event!("cache_miss", key = key, cache_type = cache_type, "retry_count" = 3);
79/// ```
80#[macro_export]
81macro_rules! event {
82 ($name:literal $(, $($attributes:tt)*)?) => {
83 $crate::CurrentSpan::add_event($name, $crate::attributes!($($($attributes)*)?))
84 };
85}
86
87/// Logs a message with the specified severity level.
88///
89/// This is the base logging macro that other severity-specific macros build upon.
90/// It allows you to specify the severity level and optional attributes.
91///
92/// # Examples
93///
94/// Log a simple message:
95/// ```rust
96/// use veecle_telemetry::log;
97/// use veecle_telemetry::protocol::Severity;
98///
99/// log!(Severity::Info, "Application started");
100/// ```
101///
102/// Log a message with attributes:
103/// ```rust
104/// use veecle_telemetry::log;
105/// use veecle_telemetry::protocol::Severity;
106///
107/// let port = 8080;
108/// let version = "1.0.0";
109/// log!(Severity::Info, "Server listening", port = port, version = version, "protocol" = "HTTP");
110/// ```
111#[macro_export]
112macro_rules! log {
113 ($severity:expr, $body:literal $(, $($attributes:tt)*)?) => {
114 $crate::log::log($severity, $body, $crate::attributes!($($($attributes)*)?))
115 };
116}
117
118/// Logs a trace-level message.
119///
120/// Trace messages are used for very detailed debugging information,
121/// typically only enabled during development or deep troubleshooting.
122///
123/// # Examples
124///
125/// Simple trace message:
126/// ```rust
127/// use veecle_telemetry::trace;
128///
129/// trace!("Entering function");
130/// ```
131///
132/// Trace message with context:
133/// ```rust
134/// use veecle_telemetry::trace;
135///
136/// let function_name = "process_request";
137/// let request_id = "req-123";
138/// trace!("Function entry", function = function_name, request_id = request_id);
139/// ```
140#[macro_export]
141macro_rules! trace {
142 ($($args:tt)*) => {
143 $crate::log!($crate::protocol::Severity::Trace, $($args)*);
144 };
145}
146
147/// Logs a debug-level message.
148///
149/// Debug messages provide detailed information about the program's execution,
150/// useful for diagnosing issues during development and testing.
151///
152/// # Examples
153///
154/// Simple debug message:
155/// ```rust
156/// use veecle_telemetry::debug;
157///
158/// debug!("Processing user request");
159/// ```
160///
161/// Debug message with variables:
162/// ```rust
163/// use veecle_telemetry::debug;
164///
165/// let user_id = 456;
166/// let action = "login";
167/// debug!("User action processed", user_id = user_id, action = action, "success" = true);
168/// ```
169#[macro_export]
170macro_rules! debug {
171 ($($args:tt)*) => {
172 $crate::log!($crate::protocol::Severity::Debug, $($args)*);
173 };
174}
175
176/// Logs an info-level message.
177///
178/// Info messages provide general information about the program's execution,
179/// suitable for normal operational logging.
180///
181/// # Examples
182///
183/// Simple info message:
184/// ```rust
185/// use veecle_telemetry::info;
186///
187/// info!("Service started successfully");
188/// ```
189///
190/// Info message with metadata:
191/// ```rust
192/// use veecle_telemetry::info;
193///
194/// let service_name = "web-server";
195/// let version = "2.1.0";
196/// info!(
197/// "Service initialization complete",
198/// service = service_name,
199/// version = version,
200/// "startup_time_ms" = 1250
201/// );
202/// ```
203#[macro_export]
204macro_rules! info {
205 ($($args:tt)*) => {
206 $crate::log!($crate::protocol::Severity::Info, $($args)*);
207 };
208}
209
210/// Logs a warning-level message.
211///
212/// Warning messages indicate potential issues or unusual conditions
213/// that don't prevent the program from continuing but should be noted.
214///
215/// # Examples
216///
217/// Simple warning message:
218/// ```rust
219/// use veecle_telemetry::warn;
220///
221/// warn!("Rate limit approaching");
222/// ```
223///
224/// Warning with context:
225/// ```rust
226/// use veecle_telemetry::warn;
227///
228/// let current_requests = 950;
229/// let limit = 1000;
230/// warn!(
231/// "High request rate detected",
232/// current_requests = current_requests,
233/// limit = limit,
234/// "utilization_percent" = 95
235/// );
236/// ```
237#[macro_export]
238macro_rules! warn {
239 ($($args:tt)*) => {
240 $crate::log!($crate::protocol::Severity::Warn, $($args)*);
241 };
242}
243
244/// Logs an error-level message.
245///
246/// Error messages indicate serious problems that have occurred
247/// but allow the program to continue running.
248///
249/// # Examples
250///
251/// Simple error message:
252/// ```rust
253/// use veecle_telemetry::error;
254///
255/// error!("Database connection failed");
256/// ```
257///
258/// Error with details:
259/// ```rust
260/// use veecle_telemetry::error;
261///
262/// let db_host = "localhost:5432";
263/// let error_code = 1001;
264/// error!(
265/// "Database operation failed",
266/// host = db_host,
267/// error_code = error_code,
268/// "retry_attempted" = true
269/// );
270/// ```
271#[macro_export]
272macro_rules! error {
273 ($($args:tt)*) => {
274 $crate::log!($crate::protocol::Severity::Error, $($args)*);
275 };
276}
277
278/// Logs a fatal-level message.
279///
280/// Fatal messages indicate critical errors that will likely cause
281/// the program to terminate or become unusable.
282///
283/// # Examples
284///
285/// Simple fatal message:
286/// ```rust
287/// use veecle_telemetry::fatal;
288///
289/// fatal!("Critical system failure");
290/// ```
291///
292/// Fatal error with context:
293/// ```rust
294/// use veecle_telemetry::fatal;
295///
296/// let component = "memory_allocator";
297/// let error_type = "out_of_memory";
298/// fatal!(
299/// "System component failure",
300/// component = component,
301/// error_type = error_type,
302/// "available_memory_mb" = 0
303/// );
304/// ```
305#[macro_export]
306macro_rules! fatal {
307 ($($args:tt)*) => {
308 $crate::log!($crate::protocol::Severity::Fatal, $($args)*);
309 };
310}
311
312/// Constructs a slice of `KeyValue` attributes.
313///
314/// This macro is primarily used when manually constructing spans.
315///
316/// # Syntax
317///
318/// The macro supports several attribute formats:
319/// - `identifier = value` - Uses the identifier as the key name
320/// - `"literal" = value` - Uses the literal string as the key name
321/// - `identifier` - Uses the identifier as both key and value
322/// - `field.subfield` - Simple dot notation for field access
323///
324/// # Examples
325///
326/// Basic usage with mixed attribute types:
327/// ```rust
328/// use veecle_telemetry::attributes;
329///
330/// let user_id = 123;
331/// let service_name = "auth-service";
332/// let attrs = attributes!(user_id = user_id, "service" = service_name, "version" = "1.0.0");
333/// ```
334///
335/// Using identifiers as both key and value:
336/// ```rust
337/// use veecle_telemetry::attributes;
338///
339/// let database = "postgresql";
340/// let timeout = 30;
341/// let attrs = attributes!(
342/// database, // equivalent to database = database
343/// timeout = timeout,
344/// "connection_pool" = "primary"
345/// );
346/// ```
347///
348/// Span construction with attributes:
349/// ```rust
350/// use veecle_telemetry::{Span, attributes};
351///
352/// let operation = "user_login";
353/// let user_id = 456;
354/// let span = Span::new(
355/// "authentication",
356/// attributes!(operation = operation, user_id = user_id, "security_level" = "high"),
357/// );
358/// ```
359///
360/// Empty attributes:
361/// ```rust
362/// use veecle_telemetry::attributes;
363/// use veecle_telemetry::value::KeyValue;
364///
365/// let attrs: &[KeyValue] = attributes!(); // Creates an empty slice
366/// ```
367#[macro_export]
368macro_rules! attributes {
369 ({ $($kvs:tt)* }) => {
370 $crate::attributes_inner!(@ { }, { $($kvs)* })
371 };
372 ($($kvs:tt)*) => {
373 $crate::attributes_inner!(@ { }, { $($kvs)* })
374 };
375}
376
377/// The actual implementation of `attributes!`, separated out to avoid accidentally recursing into
378/// the `$($tt)*` case from the inner cases.
379#[doc(hidden)]
380#[macro_export]
381macro_rules! attributes_inner {
382 // Base case, remaining tokens is empty.
383 (@ { $($val:expr,)* }, { } ) => {
384 &[ $($val,)* ]
385 };
386
387 // Recursive cases, take one key-value pair, add it to the output, and recurse on the remaining
388 // tokens.
389 (@ { $($out:expr,)* }, { $($key:ident).+ $(, $($rest:tt)*)? }) => {
390 $crate::attributes_inner!(
391 @ { $($out,)* $crate::attribute!($($key).+), },
392 { $($($rest)*)? }
393 )
394 };
395 (@ { $($out:expr,)* }, { $key:ident = $value:expr $(, $($rest:tt)*)? }) => {
396 $crate::attributes_inner!(
397 @ { $($out,)* $crate::attribute!($key = $value), },
398 { $($($rest)*)? }
399 )
400 };
401 (@ { $($out:expr,)* }, { $key:literal = $value:expr $(, $($rest:tt)*)? }) => {
402 $crate::attributes_inner!(
403 @ { $($out,)* $crate::attribute!($key = $value), },
404 { $($($rest)*)? }
405 )
406 };
407}
408
409/// Constructs a single attribute `KeyValue` pair.
410#[macro_export]
411macro_rules! attribute {
412 ($($key:ident)+ = $value:expr) => {
413 $crate::value::KeyValue::new(::core::stringify!($($key).+), $value)
414 };
415 ($key:literal = $value:expr) => {
416 $crate::value::KeyValue::new($key, $value)
417 };
418 ($($key:ident)+) => {
419 $crate::value::KeyValue::new(::core::stringify!($($key).+), $($key).+)
420 };
421}