use chrono::{DateTime, Utc};
use derive_more::Display;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use uuid::Uuid;
pub mod client;
#[derive(Debug, Display, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct TraceId(pub Uuid);
#[derive(Debug, Display, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct FlowId(pub String);
#[derive(Debug, Display, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct ExecutionId(pub Uuid);
#[derive(Debug, Display, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct EventId(pub Uuid);
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FlowVersion {
pub major: u32,
pub minor: u32,
pub patch: u32,
pub git_hash: Option<String>,
pub timestamp: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[allow(clippy::large_enum_variant)]
pub enum TracingRequest {
StartTrace {
flow_id: FlowId,
version: FlowVersion,
},
RecordEvent {
trace_id: TraceId,
event: TraceEvent,
},
GetTrace { trace_id: TraceId },
QueryTraces { query: TraceQuery },
GetFlowVersions { flow_id: FlowId },
Ping,
Subscribe { filters: SubscriptionFilters },
Unsubscribe,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TracingResponse {
TraceStarted { trace_id: TraceId },
EventRecorded {
success: bool,
error: Option<String>,
},
TraceData { trace: Option<FlowTrace> },
QueryResults {
traces: Vec<FlowTrace>,
total_count: usize,
},
FlowVersions { versions: Vec<FlowVersion> },
Pong,
EventNotification {
trace_id: TraceId,
event: TraceEvent,
},
Error { message: String, code: ErrorCode },
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ErrorCode {
NotFound,
InvalidRequest,
StorageError,
SerializationError,
Unauthorized,
InternalError,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubscriptionFilters {
pub flow_ids: Option<Vec<FlowId>>,
pub actor_ids: Option<Vec<String>>,
pub event_types: Option<Vec<TraceEventType>>,
pub status_filter: Option<Vec<ExecutionStatus>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FlowTrace {
pub trace_id: TraceId,
pub flow_id: FlowId,
pub execution_id: ExecutionId,
pub version: FlowVersion,
pub start_time: DateTime<Utc>,
pub end_time: Option<DateTime<Utc>>,
pub status: ExecutionStatus,
pub events: Vec<TraceEvent>,
pub metadata: TraceMetadata,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum ExecutionStatus {
Pending,
Running,
Completed,
Failed { error: String },
Cancelled,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TraceEvent {
pub event_id: EventId,
pub timestamp: DateTime<Utc>,
pub event_type: TraceEventType,
pub actor_id: String,
pub data: TraceEventData,
pub causality: CausalityInfo,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum TraceEventType {
ActorCreated,
ActorStarted,
ActorCompleted,
ActorFailed,
MessageSent,
MessageReceived,
StateChanged,
PortConnected,
PortDisconnected,
DataFlow { to_actor: String, to_port: String },
NetworkEvent,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TraceEventData {
pub port: Option<String>,
pub message: Option<MessageSnapshot>,
pub state_diff: Option<StateDiff>,
pub error: Option<String>,
pub performance_metrics: PerformanceMetrics,
pub custom_attributes: HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MessageSnapshot {
pub message_type: String,
pub size_bytes: usize,
pub checksum: String,
pub serialized_data: Vec<u8>, }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StateDiff {
pub before: Option<Vec<u8>>, pub after: Vec<u8>, pub diff_type: StateDiffType,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum StateDiffType {
Full,
Incremental,
MemoryOnly,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceMetrics {
pub execution_time_ns: u64,
pub memory_usage_bytes: usize,
pub cpu_usage_percent: f32,
pub queue_depth: usize,
pub throughput_msgs_per_sec: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CausalityInfo {
pub parent_event_id: Option<EventId>,
pub root_cause_event_id: EventId,
pub dependency_chain: Vec<EventId>,
pub span_id: String, }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TraceMetadata {
pub user_id: Option<String>,
pub session_id: Option<String>,
pub environment: String,
pub hostname: String,
pub process_id: u32,
pub thread_id: String,
pub tags: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TraceQuery {
pub flow_id: Option<FlowId>,
pub execution_id: Option<ExecutionId>,
pub time_range: Option<(DateTime<Utc>, DateTime<Utc>)>,
pub status: Option<ExecutionStatus>,
pub actor_filter: Option<String>,
pub limit: Option<usize>,
pub offset: Option<usize>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TraceMessage {
StoreTrace { trace: FlowTrace },
QueryTraces { query: TraceQuery },
GetTrace { trace_id: TraceId },
Subscribe { filter: SubscriptionFilters },
GetMetrics,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[allow(clippy::large_enum_variant)]
pub enum TraceResponse {
TraceStored { trace_id: TraceId },
TracesFound { traces: Vec<FlowTrace> },
TraceData { trace: FlowTrace },
Error { message: String },
Metrics { data: serde_json::Value },
}
impl TraceId {
pub fn new() -> Self {
Self(Uuid::new_v4())
}
pub fn from_uuid(uuid: Uuid) -> Self {
Self(uuid)
}
pub fn as_uuid(&self) -> &Uuid {
&self.0
}
}
impl ExecutionId {
pub fn new() -> Self {
Self(Uuid::new_v4())
}
pub fn from_uuid(uuid: Uuid) -> Self {
Self(uuid)
}
pub fn as_uuid(&self) -> &Uuid {
&self.0
}
}
impl EventId {
pub fn new() -> Self {
Self(Uuid::new_v4())
}
pub fn from_uuid(uuid: Uuid) -> Self {
Self(uuid)
}
pub fn as_uuid(&self) -> &Uuid {
&self.0
}
}
impl FlowId {
pub fn new(id: impl Into<String>) -> Self {
Self(id.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl Default for TraceId {
fn default() -> Self {
Self::new()
}
}
impl Default for ExecutionId {
fn default() -> Self {
Self::new()
}
}
impl Default for EventId {
fn default() -> Self {
Self::new()
}
}
impl Default for PerformanceMetrics {
fn default() -> Self {
Self {
execution_time_ns: 0,
memory_usage_bytes: 0,
cpu_usage_percent: 0.0,
queue_depth: 0,
throughput_msgs_per_sec: 0.0,
}
}
}
impl TraceEvent {
pub fn actor_created(actor_id: String) -> Self {
Self {
event_id: EventId::new(),
timestamp: Utc::now(),
event_type: TraceEventType::ActorCreated,
actor_id,
data: TraceEventData {
port: None,
message: None,
state_diff: None,
error: None,
performance_metrics: PerformanceMetrics::default(),
custom_attributes: HashMap::new(),
},
causality: CausalityInfo {
parent_event_id: None,
root_cause_event_id: EventId::new(),
dependency_chain: Vec::new(),
span_id: Uuid::new_v4().to_string(),
},
}
}
pub fn data_flow(
from_actor: String,
from_port: String,
to_actor: String,
to_port: String,
message_type: String,
size_bytes: usize,
) -> Self {
Self {
event_id: EventId::new(),
timestamp: Utc::now(),
event_type: TraceEventType::DataFlow { to_actor, to_port },
actor_id: from_actor,
data: TraceEventData {
port: Some(from_port),
message: Some(MessageSnapshot {
message_type,
size_bytes,
checksum: String::new(), serialized_data: Vec::new(), }),
state_diff: None,
error: None,
performance_metrics: PerformanceMetrics::default(),
custom_attributes: HashMap::new(),
},
causality: CausalityInfo {
parent_event_id: None,
root_cause_event_id: EventId::new(),
dependency_chain: Vec::new(),
span_id: Uuid::new_v4().to_string(),
},
}
}
pub fn message_sent(
actor_id: String,
port: String,
message_type: String,
size_bytes: usize,
) -> Self {
Self {
event_id: EventId::new(),
timestamp: Utc::now(),
event_type: TraceEventType::MessageSent,
actor_id,
data: TraceEventData {
port: Some(port),
message: Some(MessageSnapshot {
message_type,
size_bytes,
checksum: String::new(), serialized_data: Vec::new(), }),
state_diff: None,
error: None,
performance_metrics: PerformanceMetrics::default(),
custom_attributes: HashMap::new(),
},
causality: CausalityInfo {
parent_event_id: None,
root_cause_event_id: EventId::new(),
dependency_chain: Vec::new(),
span_id: Uuid::new_v4().to_string(),
},
}
}
pub fn actor_completed(actor_id: String) -> Self {
Self {
event_id: EventId::new(),
timestamp: Utc::now(),
event_type: TraceEventType::ActorCompleted,
actor_id,
data: TraceEventData {
port: None,
message: None,
state_diff: None,
error: None,
performance_metrics: PerformanceMetrics::default(),
custom_attributes: HashMap::new(),
},
causality: CausalityInfo {
parent_event_id: None,
root_cause_event_id: EventId::new(),
dependency_chain: Vec::new(),
span_id: Uuid::new_v4().to_string(),
},
}
}
pub fn actor_failed(actor_id: String, error: String) -> Self {
Self {
event_id: EventId::new(),
timestamp: Utc::now(),
event_type: TraceEventType::ActorFailed,
actor_id,
data: TraceEventData {
port: None,
message: None,
state_diff: None,
error: Some(error),
performance_metrics: PerformanceMetrics::default(),
custom_attributes: HashMap::new(),
},
causality: CausalityInfo {
parent_event_id: None,
root_cause_event_id: EventId::new(),
dependency_chain: Vec::new(),
span_id: Uuid::new_v4().to_string(),
},
}
}
}