use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)]
pub struct IngestionBatch {
pub batch: Vec<IngestionEvent>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct IngestionResponse {
#[serde(default)]
pub successes: Vec<IngestionSuccess>,
#[serde(default)]
pub errors: Vec<IngestionError>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct IngestionSuccess {
pub id: String,
pub status: u16,
}
#[derive(Debug, Clone, Deserialize)]
pub struct IngestionError {
pub id: String,
pub status: u16,
#[serde(default)]
pub message: Option<String>,
}
#[derive(Debug, Clone, Serialize)]
pub struct IngestionEvent {
pub id: String,
#[serde(rename = "type")]
pub kind: EventKind,
pub timestamp: String,
pub body: serde_json::Value,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum EventKind {
TraceCreate,
GenerationCreate,
GenerationUpdate,
SpanCreate,
SpanUpdate,
EventCreate,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum ObservationLevel {
Debug,
Default,
Warning,
Error,
}
#[derive(Debug, Clone, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TraceBody {
pub id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub session_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub input: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub output: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub environment: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timestamp: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ObservationBody {
pub id: String,
pub trace_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent_observation_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_time: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub end_time: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub input: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub output: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub level: Option<ObservationLevel>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status_message: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub environment: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub usage_details: Option<serde_json::Map<String, serde_json::Value>>,
}
impl IngestionEvent {
pub fn trace(
envelope_id: String,
timestamp: String,
kind: EventKind,
body: &TraceBody,
) -> Self {
Self {
id: envelope_id,
kind,
timestamp,
body: serde_json::to_value(body).unwrap_or(serde_json::Value::Null),
}
}
pub fn observation(
envelope_id: String,
timestamp: String,
kind: EventKind,
body: &ObservationBody,
) -> Self {
Self {
id: envelope_id,
kind,
timestamp,
body: serde_json::to_value(body).unwrap_or(serde_json::Value::Null),
}
}
}