plano/crates/common/src/tracing.rs

230 lines
6 KiB
Rust
Raw Normal View History

use rand::RngCore;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
pub struct ResourceSpan {
pub resource: Resource,
#[serde(rename = "scopeSpans")]
pub scope_spans: Vec<ScopeSpan>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Resource {
pub attributes: Vec<Attribute>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ScopeSpan {
scope: Scope,
spans: Vec<Span>,
}
#[derive(Serialize, Deserialize, Debug)]
struct Scope {
name: String,
version: String,
attributes: Vec<Attribute>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Span {
#[serde(rename = "traceId")]
pub trace_id: String,
#[serde(rename = "spanId")]
pub span_id: String,
#[serde(rename = "parentSpanId")]
pub parent_span_id: Option<String>, // Optional in case theres no parent span
pub name: String,
#[serde(rename = "startTimeUnixNano")]
pub start_time_unix_nano: String,
#[serde(rename = "endTimeUnixNano")]
pub end_time_unix_nano: String,
pub kind: u32,
pub attributes: Vec<Attribute>,
pub events: Option<Vec<Event>>,
}
impl Span {
pub fn new(
name: String,
2024-11-18 17:55:39 -08:00
trace_id: Option<String>,
parent_span_id: Option<String>,
start_time_unix_nano: u128,
end_time_unix_nano: u128,
) -> Self {
2024-11-18 17:55:39 -08:00
let trace_id = match trace_id {
Some(trace_id) => trace_id,
None => Span::get_random_trace_id(),
};
Span {
2024-11-18 17:55:39 -08:00
trace_id,
span_id: Span::get_random_span_id(),
parent_span_id,
name,
start_time_unix_nano: format!("{}", start_time_unix_nano),
end_time_unix_nano: format!("{}", end_time_unix_nano),
kind: 0,
attributes: Vec::new(),
events: None,
}
}
pub fn add_attribute(&mut self, key: String, value: String) {
self.attributes.push(Attribute {
key,
value: AttributeValue {
string_value: Some(value),
},
});
}
pub fn add_event(&mut self, event: Event) {
if self.events.is_none() {
self.events = Some(Vec::new());
}
self.events.as_mut().unwrap().push(event);
}
2024-11-18 17:55:39 -08:00
fn get_random_span_id() -> String {
let mut rng = rand::thread_rng();
let mut random_bytes = [0u8; 8];
rng.fill_bytes(&mut random_bytes);
hex::encode(random_bytes)
}
fn get_random_trace_id() -> String {
let mut rng = rand::thread_rng();
let mut random_bytes = [0u8; 16];
rng.fill_bytes(&mut random_bytes);
hex::encode(random_bytes)
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Event {
#[serde(rename = "timeUnixNano")]
pub time_unix_nano: String,
pub name: String,
pub attributes: Vec<Attribute>,
}
impl Event {
pub fn new(name: String, time_unix_nano: u128) -> Self {
Event {
time_unix_nano: format!("{}", time_unix_nano),
name,
attributes: Vec::new(),
}
}
pub fn add_attribute(&mut self, key: String, value: String) {
self.attributes.push(Attribute {
key,
value: AttributeValue {
string_value: Some(value),
},
});
}
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Attribute {
key: String,
value: AttributeValue,
}
#[derive(Serialize, Deserialize, Debug)]
struct AttributeValue {
#[serde(rename = "stringValue")]
string_value: Option<String>, // Use Option to handle different value types
}
#[derive(Serialize, Deserialize, Debug)]
pub struct TraceData {
#[serde(rename = "resourceSpans")]
resource_spans: Vec<ResourceSpan>,
}
impl Default for TraceData {
fn default() -> Self {
Self::new()
}
}
impl TraceData {
pub fn new() -> Self {
TraceData {
resource_spans: Vec::new(),
}
}
pub fn add_span(&mut self, span: Span) {
if self.resource_spans.is_empty() {
let resource = Resource {
attributes: vec![Attribute {
key: "service.name".to_string(),
value: AttributeValue {
string_value: Some("egress_llm_traffic".to_string()),
},
}],
};
let scope_span = ScopeSpan {
scope: Scope {
name: "default".to_string(),
version: "1.0".to_string(),
attributes: Vec::new(),
},
spans: Vec::new(),
};
let resource_span = ResourceSpan {
resource,
scope_spans: vec![scope_span],
};
self.resource_spans.push(resource_span);
}
self.resource_spans[0].scope_spans[0].spans.push(span);
}
}
2024-11-18 17:55:39 -08:00
pub struct Traceparent {
pub version: String,
pub trace_id: String,
pub parent_id: String,
pub flags: String,
}
2024-11-18 17:55:39 -08:00
impl std::fmt::Display for Traceparent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}-{}-{}-{}",
self.version, self.trace_id, self.parent_id, self.flags
)
}
}
#[derive(thiserror::Error, Debug)]
pub enum TraceparentNewError {
#[error("Invalid traceparent: \'{0}\'")]
InvalidTraceparent(String),
}
impl TryFrom<String> for Traceparent {
type Error = TraceparentNewError;
fn try_from(traceparent: String) -> Result<Self, Self::Error> {
let traceparent_tokens: Vec<&str> = traceparent.split("-").collect::<Vec<&str>>();
if traceparent_tokens.len() != 4 {
return Err(TraceparentNewError::InvalidTraceparent(traceparent));
}
Ok(Traceparent {
version: traceparent_tokens[0].to_string(),
trace_id: traceparent_tokens[1].to_string(),
parent_id: traceparent_tokens[2].to_string(),
flags: traceparent_tokens[3].to_string(),
})
}
}