use std::sync::Mutex;
use crate::types::{TraceData, TraceStatus, SpanData};
pub struct Trace {
id: String,
name: String,
status: Mutex<TraceStatus>,
started_at: i64,
ended_at: Mutex<Option<i64>>,
session_id: Option<String>,
user_id: Option<String>,
input: Option<String>,
output: Mutex<Option<String>>,
metadata: Option<serde_json::Value>,
prompt_name: Option<String>,
prompt_version: Option<String>,
spans: Mutex<Vec<SpanData>>,
}
impl Trace {
pub fn new(name: impl Into<String>) -> Self {
Self {
id: uuid::Uuid::new_v4().to_string().replace("-", ""),
name: name.into(),
status: Mutex::new(TraceStatus::Running),
started_at: now_millis(),
ended_at: Mutex::new(None),
session_id: None,
user_id: None,
input: None,
output: Mutex::new(None),
metadata: None,
prompt_name: None,
prompt_version: None,
spans: Mutex::new(Vec::new()),
}
}
pub fn session_id(mut self, id: impl Into<String>) -> Self {
self.session_id = Some(id.into());
self
}
pub fn user_id(mut self, id: impl Into<String>) -> Self {
self.user_id = Some(id.into());
self
}
pub fn input_text(mut self, input: impl Into<String>) -> Self {
self.input = Some(input.into());
self
}
pub fn prompt_name(mut self, name: impl Into<String>) -> Self {
self.prompt_name = Some(name.into());
self
}
pub fn prompt_version(mut self, version: impl Into<String>) -> Self {
self.prompt_version = Some(version.into());
self
}
pub fn set_output(&self, output: impl Into<String>) {
*self.output.lock().unwrap() = Some(output.into());
}
pub fn set_status(&self, status: TraceStatus) {
*self.status.lock().unwrap() = status;
}
pub fn end(&self) {
let mut ended = self.ended_at.lock().unwrap();
if ended.is_none() {
*ended = Some(now_millis());
}
let mut status = self.status.lock().unwrap();
if *status == TraceStatus::Running {
*status = TraceStatus::Completed;
}
}
pub(crate) fn add_span(&self, span_data: SpanData) {
self.spans.lock().unwrap().push(span_data);
}
pub fn id(&self) -> &str {
&self.id
}
pub fn name(&self) -> &str {
&self.name
}
pub fn started_at(&self) -> i64 {
self.started_at
}
pub fn span_count(&self) -> usize {
self.spans.lock().unwrap().len()
}
pub fn spans(&self) -> Vec<SpanData> {
self.spans.lock().unwrap().clone()
}
pub fn to_data(&self) -> TraceData {
TraceData {
id: self.id.clone(),
name: self.name.clone(),
status: *self.status.lock().unwrap(),
started_at: self.started_at,
ended_at: *self.ended_at.lock().unwrap(),
spans: self.spans.lock().unwrap().clone(),
session_id: self.session_id.clone(),
user_id: self.user_id.clone(),
input: self.input.clone(),
output: self.output.lock().unwrap().clone(),
metadata: self.metadata.clone(),
prompt_name: self.prompt_name.clone(),
prompt_version: self.prompt_version.clone(),
}
}
}
impl std::fmt::Debug for Trace {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Trace")
.field("id", &self.id)
.field("name", &self.name)
.field("started_at", &self.started_at)
.field("span_count", &self.span_count())
.finish()
}
}
fn now_millis() -> i64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_millis() as i64
}