#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::ops::Deref;
use serde::{Deserialize, Serialize};
use crate::SpanContext;
use crate::id::{SpanId, TraceId};
#[cfg(feature = "alloc")]
use crate::to_static::ToStatic;
use crate::types::{ListType, StringType, list_from_slice};
use crate::value::KeyValue;
pub fn attribute_list_from_slice<'a>(slice: &'a [KeyValue<'a>]) -> AttributeListType<'a> {
list_from_slice::<KeyValue<'a>>(slice)
}
pub type AttributeListType<'a> = ListType<'a, KeyValue<'a>>;
#[cfg(feature = "alloc")]
impl ToStatic for AttributeListType<'_> {
type Static = AttributeListType<'static>;
fn to_static(&self) -> Self::Static {
self.iter()
.map(|item| item.to_static())
.collect::<Vec<_>>()
.into()
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default, Serialize, Deserialize)]
pub struct ExecutionId(u128);
impl ExecutionId {
pub fn random(rng: &mut impl rand::Rng) -> Self {
Self(rng.random())
}
pub const fn from_raw(raw: u128) -> Self {
Self(raw)
}
}
impl Deref for ExecutionId {
type Target = u128;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Clone, Debug, Serialize)]
#[cfg_attr(feature = "alloc", derive(Deserialize))]
pub struct InstanceMessage<'a> {
pub execution: ExecutionId,
#[serde(borrow)]
pub message: TelemetryMessage<'a>,
}
#[cfg(feature = "alloc")]
impl ToStatic for InstanceMessage<'_> {
type Static = InstanceMessage<'static>;
fn to_static(&self) -> Self::Static {
InstanceMessage {
execution: self.execution,
message: self.message.to_static(),
}
}
}
#[derive(Clone, Debug, Serialize)]
#[cfg_attr(feature = "alloc", derive(Deserialize))]
pub enum TelemetryMessage<'a> {
Log(#[serde(borrow)] LogMessage<'a>),
TimeSync(TimeSyncMessage),
Tracing(#[serde(borrow)] TracingMessage<'a>),
}
#[cfg(feature = "alloc")]
impl ToStatic for TelemetryMessage<'_> {
type Static = TelemetryMessage<'static>;
fn to_static(&self) -> Self::Static {
match self {
TelemetryMessage::Log(msg) => TelemetryMessage::Log(msg.to_static()),
TelemetryMessage::TimeSync(msg) => TelemetryMessage::TimeSync(msg.clone()),
TelemetryMessage::Tracing(msg) => TelemetryMessage::Tracing(msg.to_static()),
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum Severity {
Trace,
Debug,
Info,
Warn,
Error,
Fatal,
}
#[derive(Clone, Debug, Serialize)]
#[cfg_attr(feature = "alloc", derive(Deserialize))]
pub struct LogMessage<'a> {
pub time_unix_nano: u64,
pub severity: Severity,
#[serde(borrow)]
pub body: StringType<'a>,
#[serde(borrow)]
pub attributes: AttributeListType<'a>,
pub trace_id: Option<TraceId>,
pub span_id: Option<SpanId>,
}
#[cfg(feature = "alloc")]
impl ToStatic for LogMessage<'_> {
type Static = LogMessage<'static>;
fn to_static(&self) -> Self::Static {
LogMessage {
time_unix_nano: self.time_unix_nano,
severity: self.severity,
body: self.body.to_static(),
attributes: self.attributes.to_static(),
trace_id: self.trace_id,
span_id: self.span_id,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TimeSyncMessage {
pub local_timestamp: u64,
pub since_epoch: u64,
}
#[derive(Clone, Debug, Serialize)]
#[cfg_attr(feature = "alloc", derive(Deserialize))]
pub enum TracingMessage<'a> {
CreateSpan(#[serde(borrow)] SpanCreateMessage<'a>),
EnterSpan(SpanEnterMessage),
ExitSpan(SpanExitMessage),
CloseSpan(SpanCloseMessage),
AddEvent(#[serde(borrow)] SpanAddEventMessage<'a>),
AddLink(SpanAddLinkMessage),
SetAttribute(#[serde(borrow)] SpanSetAttributeMessage<'a>),
}
#[cfg(feature = "alloc")]
impl ToStatic for TracingMessage<'_> {
type Static = TracingMessage<'static>;
fn to_static(&self) -> Self::Static {
match self {
TracingMessage::CreateSpan(msg) => TracingMessage::CreateSpan(msg.to_static()),
TracingMessage::EnterSpan(msg) => TracingMessage::EnterSpan(*msg),
TracingMessage::ExitSpan(msg) => TracingMessage::ExitSpan(*msg),
TracingMessage::CloseSpan(msg) => TracingMessage::CloseSpan(*msg),
TracingMessage::AddEvent(msg) => TracingMessage::AddEvent(msg.to_static()),
TracingMessage::AddLink(msg) => TracingMessage::AddLink(*msg),
TracingMessage::SetAttribute(msg) => TracingMessage::SetAttribute(msg.to_static()),
}
}
}
#[derive(Clone, Debug, Serialize)]
#[cfg_attr(feature = "alloc", derive(Deserialize))]
pub struct SpanCreateMessage<'a> {
pub trace_id: TraceId,
pub span_id: SpanId,
pub parent_span_id: Option<SpanId>,
#[serde(borrow)]
pub name: StringType<'a>,
pub start_time_unix_nano: u64,
#[serde(borrow)]
pub attributes: AttributeListType<'a>,
}
#[cfg(feature = "alloc")]
impl ToStatic for SpanCreateMessage<'_> {
type Static = SpanCreateMessage<'static>;
fn to_static(&self) -> Self::Static {
SpanCreateMessage {
trace_id: self.trace_id,
span_id: self.span_id,
parent_span_id: self.parent_span_id,
name: self.name.to_static(),
start_time_unix_nano: self.start_time_unix_nano,
attributes: self.attributes.to_static(),
}
}
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct SpanEnterMessage {
pub trace_id: TraceId,
pub span_id: SpanId,
pub time_unix_nano: u64,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct SpanExitMessage {
pub trace_id: TraceId,
pub span_id: SpanId,
pub time_unix_nano: u64,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct SpanCloseMessage {
pub trace_id: TraceId,
pub span_id: SpanId,
pub end_time_unix_nano: u64,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SpanSetAttributeMessage<'a> {
pub trace_id: TraceId,
pub span_id: SpanId,
#[serde(borrow)]
pub attribute: KeyValue<'a>,
}
#[cfg(feature = "alloc")]
impl ToStatic for SpanSetAttributeMessage<'_> {
type Static = SpanSetAttributeMessage<'static>;
fn to_static(&self) -> Self::Static {
SpanSetAttributeMessage {
trace_id: self.trace_id,
span_id: self.span_id,
attribute: self.attribute.to_static(),
}
}
}
#[derive(Clone, Debug, Serialize)]
#[cfg_attr(feature = "alloc", derive(Deserialize))]
pub struct SpanAddEventMessage<'a> {
pub trace_id: TraceId,
pub span_id: SpanId,
#[serde(borrow)]
pub name: StringType<'a>,
pub time_unix_nano: u64,
#[serde(borrow)]
pub attributes: AttributeListType<'a>,
}
#[cfg(feature = "alloc")]
impl ToStatic for SpanAddEventMessage<'_> {
type Static = SpanAddEventMessage<'static>;
fn to_static(&self) -> Self::Static {
SpanAddEventMessage {
trace_id: self.trace_id,
span_id: self.span_id,
name: self.name.to_static(),
time_unix_nano: self.time_unix_nano,
attributes: self.attributes.to_static(),
}
}
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct SpanAddLinkMessage {
pub trace_id: TraceId,
pub span_id: SpanId,
pub link: SpanContext,
}
#[cfg(test)]
mod tests {
#[cfg(feature = "alloc")]
use alloc::string::String;
use super::*;
#[test]
fn string_type_conversions() {
let static_str: StringType<'static> = "static".into();
let _event = SpanAddEventMessage {
trace_id: TraceId(0),
span_id: SpanId(0),
name: static_str,
time_unix_nano: 0,
attributes: attribute_list_from_slice(&[]),
};
let borrowed_str: StringType = "borrowed".into();
let _event = SpanAddEventMessage {
trace_id: TraceId(0),
span_id: SpanId(0),
name: borrowed_str,
time_unix_nano: 0,
attributes: attribute_list_from_slice(&[]),
};
}
#[cfg(any(feature = "std", feature = "alloc"))]
#[test]
fn string_type_with_owned_strings() {
let string = String::from("owned");
let owned: StringType<'static> = StringType::from(string);
let _event = SpanAddEventMessage {
trace_id: TraceId(0),
span_id: SpanId(0),
name: owned,
time_unix_nano: 0,
attributes: attribute_list_from_slice(&[]),
};
}
#[cfg(feature = "alloc")]
#[test]
fn to_static_conversion() {
use alloc::string::String;
use crate::value::Value;
let borrowed_name_str = "test_span";
let borrowed_name: StringType = borrowed_name_str.into();
let owned_key = String::from("test_key");
let owned_value = String::from("test_value");
let attribute = KeyValue {
key: owned_key.as_str().into(),
value: Value::String(owned_value.as_str().into()),
};
let attributes = [attribute];
let span_event = SpanAddEventMessage {
trace_id: TraceId(0),
span_id: SpanId(0),
name: borrowed_name,
time_unix_nano: 0,
attributes: attribute_list_from_slice(&attributes),
};
let tracing_message = TracingMessage::AddEvent(span_event);
let telemetry_message = TelemetryMessage::Tracing(tracing_message);
let instance_message = InstanceMessage {
execution: ExecutionId(999),
message: telemetry_message,
};
let static_message: InstanceMessage<'static> = instance_message.to_static();
if let TelemetryMessage::Tracing(TracingMessage::AddEvent(span_event)) =
&static_message.message
{
assert_eq!(span_event.name.as_ref(), "test_span");
} else {
panic!("Expected CreateSpan message");
}
}
}