1#[cfg(feature = "alloc")]
27use alloc::vec::Vec;
28use core::ops::Deref;
29
30use serde::{Deserialize, Serialize};
31
32use crate::SpanContext;
33use crate::id::{SpanId, TraceId};
34#[cfg(feature = "alloc")]
35use crate::to_static::ToStatic;
36use crate::types::{ListType, StringType, list_from_slice};
37use crate::value::KeyValue;
38
39pub fn attribute_list_from_slice<'a>(slice: &'a [KeyValue<'a>]) -> AttributeListType<'a> {
41 list_from_slice::<KeyValue<'a>>(slice)
42}
43
44pub type AttributeListType<'a> = ListType<'a, KeyValue<'a>>;
46
47#[cfg(feature = "alloc")]
48impl ToStatic for AttributeListType<'_> {
49 type Static = AttributeListType<'static>;
50
51 fn to_static(&self) -> Self::Static {
52 self.iter()
53 .map(|item| item.to_static())
54 .collect::<Vec<_>>()
55 .into()
56 }
57}
58
59#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default, Serialize, Deserialize)]
64pub struct ExecutionId(u128);
65
66impl ExecutionId {
67 pub fn random(rng: &mut impl rand::Rng) -> Self {
69 Self(rng.random())
70 }
71
72 pub const fn from_raw(raw: u128) -> Self {
77 Self(raw)
78 }
79}
80
81impl Deref for ExecutionId {
82 type Target = u128;
83
84 fn deref(&self) -> &Self::Target {
85 &self.0
86 }
87}
88
89#[derive(Clone, Debug, Serialize)]
94#[cfg_attr(feature = "alloc", derive(Deserialize))]
95pub struct InstanceMessage<'a> {
96 pub execution: ExecutionId,
98
99 #[serde(borrow)]
101 pub message: TelemetryMessage<'a>,
102}
103
104#[cfg(feature = "alloc")]
105impl ToStatic for InstanceMessage<'_> {
106 type Static = InstanceMessage<'static>;
107
108 fn to_static(&self) -> Self::Static {
109 InstanceMessage {
110 execution: self.execution,
111 message: self.message.to_static(),
112 }
113 }
114}
115
116#[derive(Clone, Debug, Serialize)]
121#[cfg_attr(feature = "alloc", derive(Deserialize))]
122pub enum TelemetryMessage<'a> {
123 Log(#[serde(borrow)] LogMessage<'a>),
125 TimeSync(TimeSyncMessage),
127 Tracing(#[serde(borrow)] TracingMessage<'a>),
129}
130
131#[cfg(feature = "alloc")]
132impl ToStatic for TelemetryMessage<'_> {
133 type Static = TelemetryMessage<'static>;
134
135 fn to_static(&self) -> Self::Static {
136 match self {
137 TelemetryMessage::Log(msg) => TelemetryMessage::Log(msg.to_static()),
138 TelemetryMessage::TimeSync(msg) => TelemetryMessage::TimeSync(msg.clone()),
139 TelemetryMessage::Tracing(msg) => TelemetryMessage::Tracing(msg.to_static()),
140 }
141 }
142}
143
144#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
149pub enum Severity {
150 Trace,
154 Debug,
158 Info,
162 Warn,
166 Error,
170 Fatal,
174}
175
176#[derive(Clone, Debug, Serialize)]
180#[cfg_attr(feature = "alloc", derive(Deserialize))]
181pub struct LogMessage<'a> {
182 pub time_unix_nano: u64,
184 pub severity: Severity,
186
187 #[serde(borrow)]
189 pub body: StringType<'a>,
190
191 #[serde(borrow)]
193 pub attributes: AttributeListType<'a>,
194
195 pub trace_id: Option<TraceId>,
197 pub span_id: Option<SpanId>,
199}
200
201#[cfg(feature = "alloc")]
202impl ToStatic for LogMessage<'_> {
203 type Static = LogMessage<'static>;
204
205 fn to_static(&self) -> Self::Static {
206 LogMessage {
207 time_unix_nano: self.time_unix_nano,
208 severity: self.severity,
209 body: self.body.to_static(),
210 attributes: self.attributes.to_static(),
211 trace_id: self.trace_id,
212 span_id: self.span_id,
213 }
214 }
215}
216
217#[derive(Clone, Debug, Serialize, Deserialize)]
222pub struct TimeSyncMessage {
223 pub local_timestamp: u64,
225 pub since_epoch: u64,
227}
228
229#[derive(Clone, Debug, Serialize)]
234#[cfg_attr(feature = "alloc", derive(Deserialize))]
235pub enum TracingMessage<'a> {
236 CreateSpan(#[serde(borrow)] SpanCreateMessage<'a>),
238 EnterSpan(SpanEnterMessage),
240 ExitSpan(SpanExitMessage),
242 CloseSpan(SpanCloseMessage),
244 AddEvent(#[serde(borrow)] SpanAddEventMessage<'a>),
246 AddLink(SpanAddLinkMessage),
248 SetAttribute(#[serde(borrow)] SpanSetAttributeMessage<'a>),
250}
251
252#[cfg(feature = "alloc")]
253impl ToStatic for TracingMessage<'_> {
254 type Static = TracingMessage<'static>;
255
256 fn to_static(&self) -> Self::Static {
257 match self {
258 TracingMessage::CreateSpan(msg) => TracingMessage::CreateSpan(msg.to_static()),
259 TracingMessage::EnterSpan(msg) => TracingMessage::EnterSpan(*msg),
260 TracingMessage::ExitSpan(msg) => TracingMessage::ExitSpan(*msg),
261 TracingMessage::CloseSpan(msg) => TracingMessage::CloseSpan(*msg),
262 TracingMessage::AddEvent(msg) => TracingMessage::AddEvent(msg.to_static()),
263 TracingMessage::AddLink(msg) => TracingMessage::AddLink(*msg),
264 TracingMessage::SetAttribute(msg) => TracingMessage::SetAttribute(msg.to_static()),
265 }
266 }
267}
268
269#[derive(Clone, Debug, Serialize)]
274#[cfg_attr(feature = "alloc", derive(Deserialize))]
275pub struct SpanCreateMessage<'a> {
276 pub trace_id: TraceId,
278 pub span_id: SpanId,
280 pub parent_span_id: Option<SpanId>,
282
283 #[serde(borrow)]
285 pub name: StringType<'a>,
286
287 pub start_time_unix_nano: u64,
289
290 #[serde(borrow)]
292 pub attributes: AttributeListType<'a>,
293}
294
295#[cfg(feature = "alloc")]
296impl ToStatic for SpanCreateMessage<'_> {
297 type Static = SpanCreateMessage<'static>;
298
299 fn to_static(&self) -> Self::Static {
300 SpanCreateMessage {
301 trace_id: self.trace_id,
302 span_id: self.span_id,
303 parent_span_id: self.parent_span_id,
304 name: self.name.to_static(),
305 start_time_unix_nano: self.start_time_unix_nano,
306 attributes: self.attributes.to_static(),
307 }
308 }
309}
310
311#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
313pub struct SpanEnterMessage {
314 pub trace_id: TraceId,
316 pub span_id: SpanId,
318
319 pub time_unix_nano: u64,
321}
322
323#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
325pub struct SpanExitMessage {
326 pub trace_id: TraceId,
328 pub span_id: SpanId,
330
331 pub time_unix_nano: u64,
333}
334
335#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
337pub struct SpanCloseMessage {
338 pub trace_id: TraceId,
340 pub span_id: SpanId,
342
343 pub end_time_unix_nano: u64,
345}
346
347#[derive(Clone, Debug, Serialize, Deserialize)]
349pub struct SpanSetAttributeMessage<'a> {
350 pub trace_id: TraceId,
352 pub span_id: SpanId,
354
355 #[serde(borrow)]
357 pub attribute: KeyValue<'a>,
358}
359
360#[cfg(feature = "alloc")]
361impl ToStatic for SpanSetAttributeMessage<'_> {
362 type Static = SpanSetAttributeMessage<'static>;
363
364 fn to_static(&self) -> Self::Static {
365 SpanSetAttributeMessage {
366 trace_id: self.trace_id,
367 span_id: self.span_id,
368 attribute: self.attribute.to_static(),
369 }
370 }
371}
372
373#[derive(Clone, Debug, Serialize)]
375#[cfg_attr(feature = "alloc", derive(Deserialize))]
376pub struct SpanAddEventMessage<'a> {
377 pub trace_id: TraceId,
379 pub span_id: SpanId,
381
382 #[serde(borrow)]
384 pub name: StringType<'a>,
385 pub time_unix_nano: u64,
387
388 #[serde(borrow)]
390 pub attributes: AttributeListType<'a>,
391}
392
393#[cfg(feature = "alloc")]
394impl ToStatic for SpanAddEventMessage<'_> {
395 type Static = SpanAddEventMessage<'static>;
396
397 fn to_static(&self) -> Self::Static {
398 SpanAddEventMessage {
399 trace_id: self.trace_id,
400 span_id: self.span_id,
401 name: self.name.to_static(),
402 time_unix_nano: self.time_unix_nano,
403 attributes: self.attributes.to_static(),
404 }
405 }
406}
407
408#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
413pub struct SpanAddLinkMessage {
414 pub trace_id: TraceId,
416 pub span_id: SpanId,
418
419 pub link: SpanContext,
421}
422
423#[cfg(test)]
424#[cfg_attr(coverage_nightly, coverage(off))]
425mod tests {
426 #[cfg(feature = "alloc")]
427 use alloc::string::String;
428
429 use super::*;
430
431 #[test]
432 fn string_type_conversions() {
433 let static_str: StringType<'static> = "static".into();
434
435 let _event = SpanAddEventMessage {
436 trace_id: TraceId(0),
437 span_id: SpanId(0),
438 name: static_str,
439 time_unix_nano: 0,
440 attributes: attribute_list_from_slice(&[]),
441 };
442
443 let borrowed_str: StringType = "borrowed".into();
444
445 let _event = SpanAddEventMessage {
446 trace_id: TraceId(0),
447 span_id: SpanId(0),
448 name: borrowed_str,
449 time_unix_nano: 0,
450 attributes: attribute_list_from_slice(&[]),
451 };
452 }
453
454 #[cfg(any(feature = "std", feature = "alloc"))]
455 #[test]
456 fn string_type_with_owned_strings() {
457 let string = String::from("owned");
458 let owned: StringType<'static> = StringType::from(string);
459
460 let _event = SpanAddEventMessage {
461 trace_id: TraceId(0),
462 span_id: SpanId(0),
463 name: owned,
464 time_unix_nano: 0,
465 attributes: attribute_list_from_slice(&[]),
466 };
467 }
468
469 #[cfg(feature = "alloc")]
470 #[test]
471 fn to_static_conversion() {
472 use alloc::string::String;
473
474 use crate::value::Value;
475
476 let borrowed_name_str = "test_span";
478 let borrowed_name: StringType = borrowed_name_str.into();
479
480 let owned_key = String::from("test_key");
481 let owned_value = String::from("test_value");
482 let attribute = KeyValue {
483 key: owned_key.as_str().into(),
484 value: Value::String(owned_value.as_str().into()),
485 };
486
487 let attributes = [attribute];
488 let span_event = SpanAddEventMessage {
489 trace_id: TraceId(0),
490 span_id: SpanId(0),
491 name: borrowed_name,
492 time_unix_nano: 0,
493 attributes: attribute_list_from_slice(&attributes),
494 };
495
496 let tracing_message = TracingMessage::AddEvent(span_event);
497 let telemetry_message = TelemetryMessage::Tracing(tracing_message);
498 let instance_message = InstanceMessage {
499 execution: ExecutionId(999),
500 message: telemetry_message,
501 };
502
503 let static_message: InstanceMessage<'static> = instance_message.to_static();
504
505 if let TelemetryMessage::Tracing(TracingMessage::AddEvent(span_event)) =
507 &static_message.message
508 {
509 assert_eq!(span_event.name.as_ref(), "test_span");
510 } else {
511 panic!("Expected CreateSpan message");
512 }
513 }
514}