veecle_telemetry/protocol/
base.rs

1//! Core protocol type definitions and storage family trait.
2//!
3//! This module defines the core data structures used for telemetry message exchange.
4//! It includes message types for logging, tracing, and time synchronization, as well
5//! as supporting types for execution tracking and attribute management.
6//!
7//! # Message Types
8//!
9//! The protocol supports several categories of telemetry messages:
10//!
11//! - **Log Messages** - Structured logging with severity levels and attributes
12//! - **Tracing Messages** - Distributed tracing with spans, events, and links
13//! - **Time Sync Messages** - Time synchronization between systems
14//!
15//! # Thread Tracking
16//!
17//! Each message is associated with a [`ThreadId`] that uniquely identifies the thread it came from
18//! (globally unique across all processes).
19//! This allows telemetry data from multiple threads to be correlated and analyzed separately.
20
21use serde::{Deserialize, Serialize};
22
23pub use crate::SpanContext;
24pub use crate::id::{ProcessId, SpanId, ThreadId};
25
26pub(crate) trait Sealed {}
27
28#[expect(private_bounds, reason = "sealed trait")]
29/// A trait defining how data is stored in different contexts.
30///
31/// This trait allows the same protocol messages to be used with different storage strategies, see
32/// the [main protocol module][super] docs for more details on the strategies provided.
33///
34/// # Examples
35///
36/// ```rust
37/// use veecle_telemetry::protocol::base::StorageFamily;
38/// use veecle_telemetry::protocol::transient::Transient;
39///
40/// // The Transient family uses references
41/// let message: <Transient as StorageFamily>::String<'_> = "hello";
42/// ```
43pub trait StorageFamily: Clone + core::fmt::Debug + Sealed {
44    /// The string type for this storage family.
45    type String<'a>: AsRef<str> + Clone + core::fmt::Debug + serde::Serialize
46    where
47        Self: 'a;
48
49    /// The list type for this storage family.
50    type List<'a, T: Clone + core::fmt::Debug + serde::Serialize + 'a>: AsRef<[T]>
51        + Clone
52        + core::fmt::Debug
53        + serde::Serialize
54    where
55        Self: 'a;
56
57    /// The value type for this storage family.
58    type Value<'a>: Clone + core::fmt::Debug + serde::Serialize
59    where
60        Self: 'a;
61}
62
63/// A key-value attribute pair used in telemetry data.
64///
65/// Key-value pairs provide additional context for spans, events, and log messages.
66///
67/// # Examples
68///
69/// ```rust
70/// use veecle_telemetry::protocol::transient::KeyValue;
71///
72/// // Create attributes with different value types
73/// let user_id = KeyValue::new("user_id", 123);
74/// let username = KeyValue::new("username", "alice");
75/// let is_active = KeyValue::new("is_active", true);
76/// let score = KeyValue::new("score", 95.5);
77/// ```
78#[derive(Clone, Debug, Serialize, Deserialize)]
79#[serde(bound(
80    deserialize = "F::String<'a>: serde::de::DeserializeOwned, F::Value<'a>: serde::de::DeserializeOwned"
81))]
82pub struct KeyValue<'a, F>
83where
84    F: StorageFamily + 'a,
85{
86    /// The attribute key (name).
87    pub key: F::String<'a>,
88
89    /// The attribute value.
90    pub value: F::Value<'a>,
91}
92
93impl<'a, F> KeyValue<'a, F>
94where
95    F: StorageFamily + 'a,
96{
97    /// Creates a new key-value attribute pair.
98    ///
99    /// # Arguments
100    ///
101    /// * `key` - The attribute key (name)
102    /// * `value` - The attribute value
103    ///
104    /// # Examples
105    ///
106    /// ```rust
107    /// use veecle_telemetry::protocol::transient::KeyValue;
108    ///
109    /// let user_id = KeyValue::new("user_id", 123);
110    /// let username = KeyValue::new("username", "alice");
111    /// ```
112    pub fn new<K, V>(key: K, value: V) -> Self
113    where
114        K: Into<F::String<'a>>,
115        V: Into<F::Value<'a>>,
116    {
117        Self {
118            key: key.into(),
119            value: value.into(),
120        }
121    }
122}
123
124impl<'a, F> core::fmt::Display for KeyValue<'a, F>
125where
126    F: StorageFamily + 'a,
127    F::Value<'a>: core::fmt::Display,
128{
129    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
130        write!(f, "{}: {}", self.key.as_ref(), self.value)
131    }
132}
133/// A telemetry message associated with a specific execution thread.
134///
135/// This structure wraps a telemetry message with its execution context,
136/// allowing messages from different executions to be properly correlated.
137#[derive(Clone, Debug, Serialize, Deserialize)]
138#[serde(bound(deserialize = "TelemetryMessage<'a, F>: serde::de::DeserializeOwned"))]
139pub struct InstanceMessage<'a, F>
140where
141    F: StorageFamily + 'a,
142{
143    /// The thread this message belongs to.
144    pub thread_id: ThreadId,
145
146    /// The telemetry message content.
147    pub message: TelemetryMessage<'a, F>,
148}
149
150/// An enumeration of all possible telemetry message types.
151///
152/// This enum represents the different categories of telemetry data that can be
153/// collected and exported by the system.
154#[derive(Clone, Debug, Serialize, Deserialize)]
155#[serde(bound(
156    deserialize = "LogMessage<'a, F>: serde::de::DeserializeOwned, TracingMessage<'a, F>: serde::de::DeserializeOwned"
157))]
158pub enum TelemetryMessage<'a, F>
159where
160    F: StorageFamily + 'a,
161{
162    /// A structured log message with severity and attributes.
163    Log(LogMessage<'a, F>),
164
165    /// A time synchronization message for clock coordination.
166    TimeSync(TimeSyncMessage),
167
168    /// A distributed tracing message (spans, events, links).
169    Tracing(TracingMessage<'a, F>),
170}
171
172/// Log message severity levels.
173///
174/// These levels follow standard logging conventions, ordered from most verbose
175/// to most critical.
176#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
177pub enum Severity {
178    /// The "trace" level.
179    ///
180    /// Designates very low priority, often extremely verbose, information.
181    Trace,
182
183    /// The "debug" level.
184    ///
185    /// Designates lower priority information.
186    Debug,
187
188    /// The "info" level.
189    ///
190    /// Designates useful information.
191    Info,
192
193    /// The "warn" level.
194    ///
195    /// Designates hazardous situations.
196    Warn,
197
198    /// The "error" level.
199    ///
200    /// Designates very serious errors.
201    Error,
202
203    /// The "fatal" level.
204    ///
205    /// Designates critical failures that might crash the program.
206    Fatal,
207}
208
209/// A structured log message with severity, timestamp, and attributes.
210///
211/// Log messages can be optionally correlated with traces by including trace and span IDs when available.
212#[derive(Clone, Debug, Serialize, Deserialize)]
213#[serde(bound(
214    deserialize = "F::String<'a>: serde::de::DeserializeOwned, F::List<'a, KeyValue<'a, F>>: serde::de::DeserializeOwned"
215))]
216pub struct LogMessage<'a, F>
217where
218    F: StorageFamily + 'a,
219{
220    /// Timestamp in nanoseconds since Unix epoch (or system start)
221    pub time_unix_nano: u64,
222
223    /// The severity level of this log message
224    pub severity: Severity,
225
226    /// The message body
227    pub body: F::String<'a>,
228
229    /// Key-value attributes providing additional context
230    pub attributes: F::List<'a, KeyValue<'a, F>>,
231}
232
233/// A time synchronization message for coordinating clocks between systems.
234///
235/// This message contains both local time and absolute time information,
236/// allowing downstream systems to correlate local timestamps with real-world time.
237#[derive(Clone, Debug, Serialize, Deserialize)]
238pub struct TimeSyncMessage {
239    /// Local timestamp in system-specific units.
240    pub local_timestamp: u64,
241
242    /// Time since Unix epoch in nanoseconds.
243    pub since_epoch: u64,
244}
245
246/// Messages related to distributed tracing operations.
247///
248/// This enum encompasses all the different types of tracing messages that can be
249/// generated during span lifecycle management and tracing operations.
250#[derive(Clone, Debug, Serialize, Deserialize)]
251#[serde(bound(
252    deserialize = "SpanCreateMessage<'a, F>: serde::de::DeserializeOwned, SpanAddEventMessage<'a, F>: serde::de::DeserializeOwned, SpanSetAttributeMessage<'a, F>: serde::de::DeserializeOwned"
253))]
254pub enum TracingMessage<'a, F>
255where
256    F: StorageFamily + 'a,
257{
258    /// A new span has been created.
259    CreateSpan(SpanCreateMessage<'a, F>),
260
261    /// A span has been entered (made current).
262    EnterSpan(SpanEnterMessage),
263
264    /// A span has been exited (no longer current).
265    ExitSpan(SpanExitMessage),
266
267    /// A span has been closed (completed).
268    CloseSpan(SpanCloseMessage),
269
270    /// An event has been added to a span.
271    AddEvent(SpanAddEventMessage<'a, F>),
272
273    /// A link has been added to a span.
274    AddLink(SpanAddLinkMessage),
275
276    /// An attribute has been set on a span.
277    SetAttribute(SpanSetAttributeMessage<'a, F>),
278}
279
280/// Message indicating the creation of a new span.
281///
282/// This message provides all the information needed to create a new span
283/// in the trace, including its identity, timing, and initial attributes.
284#[derive(Clone, Debug, Serialize, Deserialize)]
285#[serde(bound(
286    deserialize = "F::String<'a>: serde::de::DeserializeOwned, F::List<'a, KeyValue<'a, F>>: serde::de::DeserializeOwned"
287))]
288pub struct SpanCreateMessage<'a, F>
289where
290    F: StorageFamily + 'a,
291{
292    /// The unique identifier (within the associated process) for this span.
293    pub span_id: SpanId,
294
295    /// The name of the span.
296    pub name: F::String<'a>,
297
298    /// Timestamp when the span was started.
299    pub start_time_unix_nano: u64,
300
301    /// Initial attributes attached to the span.
302    pub attributes: F::List<'a, KeyValue<'a, F>>,
303}
304
305/// Message indicating a span has been entered.
306#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
307pub struct SpanEnterMessage {
308    /// The span being entered.
309    pub span_id: SpanId,
310
311    /// Timestamp when the span was entered.
312    pub time_unix_nano: u64,
313}
314
315/// Message indicating a span has been exited.
316#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
317pub struct SpanExitMessage {
318    /// The span being exited.
319    pub span_id: SpanId,
320
321    /// Timestamp when the span was exited.
322    pub time_unix_nano: u64,
323}
324
325/// Message indicating a span has been closed (completed).
326#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
327pub struct SpanCloseMessage {
328    /// The span being closed.
329    pub span_id: SpanId,
330
331    /// Timestamp when the span was closed.
332    pub end_time_unix_nano: u64,
333}
334
335/// Message indicating an attribute has been set on a span.
336#[derive(Clone, Debug, Serialize, Deserialize)]
337#[serde(bound(deserialize = "KeyValue<'a, F>: serde::de::DeserializeOwned"))]
338pub struct SpanSetAttributeMessage<'a, F>
339where
340    F: StorageFamily + 'a,
341{
342    /// The span the attribute is being set on, if [`None`] then this applies to the "current span"
343    /// as determined by tracking [`SpanEnterMessage`] and [`SpanExitMessage`] pairs.
344    pub span_id: Option<SpanId>,
345
346    /// The attribute being set.
347    pub attribute: KeyValue<'a, F>,
348}
349
350/// Message indicating an event has been added to a span.
351#[derive(Clone, Debug, Serialize, Deserialize)]
352#[serde(bound(
353    deserialize = "F::String<'a>: serde::de::DeserializeOwned, F::List<'a, KeyValue<'a, F>>: serde::de::DeserializeOwned"
354))]
355pub struct SpanAddEventMessage<'a, F>
356where
357    F: StorageFamily + 'a,
358{
359    /// The span the event is being added to, if [`None`] then this applies to the "current span"
360    /// as determined by tracking [`SpanEnterMessage`] and [`SpanExitMessage`] pairs.
361    pub span_id: Option<SpanId>,
362
363    /// The name of the event.
364    pub name: F::String<'a>,
365
366    /// Timestamp when the event occurred.
367    pub time_unix_nano: u64,
368
369    /// Attributes providing additional context for the event.
370    pub attributes: F::List<'a, KeyValue<'a, F>>,
371}
372
373/// Message indicating a link has been added to a span.
374///
375/// Links connect spans across different traces, representing relationships
376/// that are not parent-child hierarchies.
377#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
378pub struct SpanAddLinkMessage {
379    /// The span the link is being added to, if [`None`] then this applies to the "current span"
380    /// as determined by tracking [`SpanEnterMessage`] and [`SpanExitMessage`] pairs.
381    pub span_id: Option<SpanId>,
382
383    /// The span context being linked to.
384    pub link: SpanContext,
385}