use crate::span::vec_map::VecMap;
use crate::span::{BytesData, SliceData, TraceData};
pub use thin_vec::ThinVec;
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum SpanKind {
#[default]
Internal = 1,
Server = 2,
Client = 3,
Producer = 4,
Consumer = 5,
}
impl SpanKind {
pub fn from_meta(s: &str) -> Self {
match s {
"server" => SpanKind::Server,
"client" => SpanKind::Client,
"producer" => SpanKind::Producer,
"consumer" => SpanKind::Consumer,
_ => SpanKind::Internal,
}
}
pub fn as_meta_str(&self) -> &'static str {
match self {
SpanKind::Internal => "internal",
SpanKind::Server => "server",
SpanKind::Client => "client",
SpanKind::Producer => "producer",
SpanKind::Consumer => "consumer",
}
}
}
impl From<u32> for SpanKind {
fn from(kind: u32) -> Self {
match kind {
2 => SpanKind::Server,
3 => SpanKind::Client,
4 => SpanKind::Producer,
5 => SpanKind::Consumer,
_ => SpanKind::Internal,
}
}
}
#[derive(Debug)]
pub enum AttributeValue<T: TraceData> {
String(T::Text),
Float(f64),
Int(i64),
Bool(bool),
Bytes(T::Bytes),
KeyValue(VecMap<T::Text, AttributeValue<T>>),
List(Vec<AttributeValue<T>>),
}
impl<T: TraceData> PartialEq for AttributeValue<T> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(AttributeValue::String(a), AttributeValue::String(b)) => a == b,
(AttributeValue::Float(a), AttributeValue::Float(b)) => a == b,
(AttributeValue::Int(a), AttributeValue::Int(b)) => a == b,
(AttributeValue::Bool(a), AttributeValue::Bool(b)) => a == b,
(AttributeValue::Bytes(a), AttributeValue::Bytes(b)) => a == b,
(AttributeValue::KeyValue(a), AttributeValue::KeyValue(b)) => a.slow_compare(b),
(AttributeValue::List(a), AttributeValue::List(b)) => a == b,
_ => false,
}
}
}
#[derive(Debug, Default)]
pub struct Span<T: TraceData> {
pub service: T::Text,
pub name: T::Text,
pub resource: T::Text,
pub r#type: T::Text,
pub span_id: u64,
pub parent_id: u64,
pub start: i64,
pub duration: i64,
pub error: bool,
pub span_kind: SpanKind,
pub env: T::Text,
pub version: T::Text,
pub component: T::Text,
pub attributes: VecMap<T::Text, AttributeValue<T>>,
pub span_links: ThinVec<SpanLink<T>>,
pub span_events: ThinVec<SpanEvent<T>>,
}
#[derive(Debug, Default)]
pub struct SpanLink<T: TraceData> {
pub trace_id: [u8; 16],
pub span_id: u64,
pub attributes: VecMap<T::Text, AttributeValue<T>>,
pub tracestate: T::Text,
pub flags: u32,
}
#[derive(Debug, Default)]
pub struct SpanEvent<T: TraceData> {
pub time_unix_nano: u64,
pub name: T::Text,
pub attributes: VecMap<T::Text, AttributeValue<T>>,
}
#[derive(Debug, Default)]
pub struct TraceChunk<T: TraceData> {
pub trace_id: [u8; 16],
pub priority: Option<i32>,
pub origin: T::Text,
pub sampling_mechanism: Option<u32>,
pub dropped_trace: bool,
pub attributes: VecMap<T::Text, AttributeValue<T>>,
pub spans: Vec<Span<T>>,
}
#[derive(Debug, Default)]
pub struct TracerPayload<T: TraceData> {
pub container_id: T::Text,
pub language_name: T::Text,
pub language_version: T::Text,
pub tracer_version: T::Text,
pub runtime_id: T::Text,
pub env: T::Text,
pub hostname: T::Text,
pub app_version: T::Text,
pub attributes: VecMap<T::Text, AttributeValue<T>>,
pub chunks: Vec<TraceChunk<T>>,
}
pub type SpanBytes = Span<BytesData>;
pub type SpanLinkBytes = SpanLink<BytesData>;
pub type SpanEventBytes = SpanEvent<BytesData>;
pub type AttributeValueBytes = AttributeValue<BytesData>;
pub type TraceChunkBytes = TraceChunk<BytesData>;
pub type TracerPayloadBytes = TracerPayload<BytesData>;
pub type SpanSlice<'a> = Span<SliceData<'a>>;
pub type SpanLinkSlice<'a> = SpanLink<SliceData<'a>>;
pub type SpanEventSlice<'a> = SpanEvent<SliceData<'a>>;
pub type AttributeValueSlice<'a> = AttributeValue<SliceData<'a>>;
pub type TraceChunkSlice<'a> = TraceChunk<SliceData<'a>>;
pub type TracerPayloadSlice<'a> = TracerPayload<SliceData<'a>>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn span_kind_default_is_internal() {
assert_eq!(SpanKind::default(), SpanKind::Internal);
}
#[test]
fn span_kind_from_meta() {
assert_eq!(SpanKind::from_meta("server"), SpanKind::Server);
assert_eq!(SpanKind::from_meta("client"), SpanKind::Client);
assert_eq!(SpanKind::from_meta("producer"), SpanKind::Producer);
assert_eq!(SpanKind::from_meta("consumer"), SpanKind::Consumer);
assert_eq!(SpanKind::from_meta("internal"), SpanKind::Internal);
assert_eq!(SpanKind::from_meta(""), SpanKind::Internal);
assert_eq!(SpanKind::from_meta("anything-else"), SpanKind::Internal);
}
#[test]
fn span_kind_repr_matches_otel_spec() {
assert_eq!(SpanKind::Internal as u32, 1);
assert_eq!(SpanKind::Server as u32, 2);
assert_eq!(SpanKind::Client as u32, 3);
assert_eq!(SpanKind::Producer as u32, 4);
assert_eq!(SpanKind::Consumer as u32, 5);
}
#[test]
fn span_default_has_internal_kind() {
let s = SpanBytes::default();
assert_eq!(s.span_kind, SpanKind::Internal);
assert!(!s.error);
assert!(s.attributes.is_empty());
}
}