1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct Span {
7 pub trace_id: String,
8 pub span_id: String,
9 pub parent_span_id: Option<String>,
10 pub service: String,
11 pub operation: String,
12 pub start_time: DateTime<Utc>,
13 pub end_time: DateTime<Utc>,
14 pub duration_ms: f64,
15 pub status: SpanStatus,
16 pub attributes: HashMap<String, String>,
17 pub events: Vec<SpanEvent>,
18 #[serde(default)]
22 pub kind: SpanKind,
23 #[serde(default, skip_serializing_if = "Option::is_none")]
25 pub llm: Option<LlmSpan>,
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
31#[serde(rename_all = "lowercase")]
32pub enum SpanKind {
33 #[default]
34 Internal,
35 Server,
36 Client,
37 Producer,
38 Consumer,
39 Llm,
40}
41
42impl std::fmt::Display for SpanKind {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 let s = match self {
45 SpanKind::Internal => "internal",
46 SpanKind::Server => "server",
47 SpanKind::Client => "client",
48 SpanKind::Producer => "producer",
49 SpanKind::Consumer => "consumer",
50 SpanKind::Llm => "llm",
51 };
52 write!(f, "{s}")
53 }
54}
55
56impl SpanKind {
57 pub fn from_str(s: &str) -> Self {
58 match s.to_lowercase().as_str() {
59 "server" => SpanKind::Server,
60 "client" => SpanKind::Client,
61 "producer" => SpanKind::Producer,
62 "consumer" => SpanKind::Consumer,
63 "llm" => SpanKind::Llm,
64 _ => SpanKind::Internal,
65 }
66 }
67}
68
69#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
71#[serde(rename_all = "lowercase")]
72pub enum LlmOperation {
73 #[default]
74 Chat,
75 Completion,
76 Embedding,
77 Tool,
78 Other,
79}
80
81impl LlmOperation {
82 pub fn from_str(s: &str) -> Self {
84 match s.to_lowercase().as_str() {
85 "chat" => LlmOperation::Chat,
86 "text_completion" | "completion" => LlmOperation::Completion,
87 "embeddings" | "embedding" => LlmOperation::Embedding,
88 "execute_tool" | "tool" => LlmOperation::Tool,
89 _ => LlmOperation::Other,
90 }
91 }
92}
93
94#[derive(Debug, Clone, Default, Serialize, Deserialize)]
99pub struct LlmSpan {
100 pub provider: String,
101 pub model: String,
102 pub operation: LlmOperation,
103
104 #[serde(skip_serializing_if = "Option::is_none")]
105 pub input_tokens: Option<u32>,
106 #[serde(skip_serializing_if = "Option::is_none")]
107 pub output_tokens: Option<u32>,
108 #[serde(skip_serializing_if = "Option::is_none")]
109 pub total_tokens: Option<u32>,
110 #[serde(skip_serializing_if = "Option::is_none")]
111 pub cost_usd: Option<f64>,
112
113 #[serde(skip_serializing_if = "Option::is_none")]
115 pub ttft_ms: Option<f64>,
116 #[serde(skip_serializing_if = "Option::is_none")]
118 pub inter_token_ms: Option<f64>,
119
120 #[serde(skip_serializing_if = "Option::is_none")]
121 pub prompt_sha256: Option<String>,
122 #[serde(skip_serializing_if = "Option::is_none")]
123 pub completion_sha256: Option<String>,
124
125 #[serde(skip_serializing_if = "Option::is_none")]
126 pub finish_reason: Option<String>,
127 #[serde(skip_serializing_if = "Option::is_none")]
128 pub temperature: Option<f64>,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
132#[serde(rename_all = "lowercase")]
133pub enum SpanStatus {
134 Ok,
135 Error,
136 Unset,
137}
138
139impl std::fmt::Display for SpanStatus {
140 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141 match self {
142 SpanStatus::Ok => write!(f, "ok"),
143 SpanStatus::Error => write!(f, "error"),
144 SpanStatus::Unset => write!(f, "unset"),
145 }
146 }
147}
148
149impl SpanStatus {
150 pub fn from_str(s: &str) -> Self {
151 match s.to_lowercase().as_str() {
152 "ok" => SpanStatus::Ok,
153 "error" => SpanStatus::Error,
154 _ => SpanStatus::Unset,
155 }
156 }
157}
158
159#[derive(Debug, Clone, Serialize, Deserialize)]
160pub struct SpanEvent {
161 pub name: String,
162 pub timestamp: DateTime<Utc>,
163 pub attributes: HashMap<String, String>,
164}
165
166#[derive(Debug, Clone, Serialize, Deserialize)]
167pub struct TraceComment {
168 pub id: String,
169 pub trace_id: String,
170 pub span_id: Option<String>,
171 pub author: String,
172 pub body: String,
173 pub created_at: String,
174}
175
176#[derive(Debug, Clone, Default, Serialize, Deserialize)]
177pub struct TraceQuery {
178 pub service: Option<String>,
179 pub operation: Option<String>,
180 pub min_duration_ms: Option<f64>,
181 pub max_duration_ms: Option<f64>,
182 pub status: Option<String>,
183 pub last_seconds: Option<i64>,
184 pub limit: Option<u32>,
185 #[serde(default)]
188 pub attributes: Vec<(String, String)>,
189 #[serde(default)]
193 pub text: Option<String>,
194}
195
196#[derive(Debug, Clone, Serialize, Deserialize)]
198pub struct ServiceInfo {
199 pub name: String,
200 pub span_count: i64,
201 pub trace_count: i64,
202 pub avg_duration_ms: f64,
203 pub error_rate: f64,
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
209pub struct LogRecord {
210 pub timestamp: DateTime<Utc>,
211 pub observed_timestamp: DateTime<Utc>,
212 pub trace_id: Option<String>,
213 pub span_id: Option<String>,
214 pub severity: LogSeverity,
215 pub severity_text: String,
216 pub body: String,
219 pub service: String,
220 pub attributes: HashMap<String, String>,
221 #[serde(default, skip_serializing_if = "Option::is_none")]
225 pub body_sha256: Option<String>,
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
229#[serde(rename_all = "lowercase")]
230pub enum LogSeverity {
231 Trace,
232 Debug,
233 Info,
234 Warn,
235 Error,
236 Fatal,
237 Unspecified,
238}
239
240impl std::fmt::Display for LogSeverity {
241 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
242 match self {
243 LogSeverity::Trace => write!(f, "trace"),
244 LogSeverity::Debug => write!(f, "debug"),
245 LogSeverity::Info => write!(f, "info"),
246 LogSeverity::Warn => write!(f, "warn"),
247 LogSeverity::Error => write!(f, "error"),
248 LogSeverity::Fatal => write!(f, "fatal"),
249 LogSeverity::Unspecified => write!(f, "unspecified"),
250 }
251 }
252}
253
254impl LogSeverity {
255 pub fn from_str(s: &str) -> Self {
256 match s.to_lowercase().as_str() {
257 "trace" => LogSeverity::Trace,
258 "debug" => LogSeverity::Debug,
259 "info" => LogSeverity::Info,
260 "warn" => LogSeverity::Warn,
261 "error" => LogSeverity::Error,
262 "fatal" => LogSeverity::Fatal,
263 _ => LogSeverity::Unspecified,
264 }
265 }
266
267 pub fn from_severity_number(n: i32) -> Self {
268 match n {
269 1..=4 => LogSeverity::Trace,
270 5..=8 => LogSeverity::Debug,
271 9..=12 => LogSeverity::Info,
272 13..=16 => LogSeverity::Warn,
273 17..=20 => LogSeverity::Error,
274 21..=24 => LogSeverity::Fatal,
275 _ => LogSeverity::Unspecified,
276 }
277 }
278}
279
280#[derive(Debug, Clone, Serialize, Deserialize)]
283pub struct MetricPoint {
284 pub timestamp: DateTime<Utc>,
285 pub service: String,
286 pub name: String,
287 pub metric_type: MetricType,
288 pub value: f64,
289 pub unit: String,
290 pub attributes: HashMap<String, String>,
291}
292
293#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
294#[serde(rename_all = "lowercase")]
295pub enum MetricType {
296 Gauge,
297 Sum,
298 Histogram,
299 Summary,
300 Unknown,
301}
302
303impl std::fmt::Display for MetricType {
304 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
305 match self {
306 MetricType::Gauge => write!(f, "gauge"),
307 MetricType::Sum => write!(f, "sum"),
308 MetricType::Histogram => write!(f, "histogram"),
309 MetricType::Summary => write!(f, "summary"),
310 MetricType::Unknown => write!(f, "unknown"),
311 }
312 }
313}
314
315impl MetricType {
316 pub fn from_str(s: &str) -> Self {
317 match s.to_lowercase().as_str() {
318 "gauge" => MetricType::Gauge,
319 "sum" => MetricType::Sum,
320 "histogram" => MetricType::Histogram,
321 "summary" => MetricType::Summary,
322 _ => MetricType::Unknown,
323 }
324 }
325}
326
327#[derive(Debug, Clone, Default, Serialize, Deserialize)]
328pub struct MetricQuery {
329 pub service: Option<String>,
330 pub name: Option<String>,
331 pub metric_type: Option<String>,
332 pub last_seconds: Option<i64>,
333 pub limit: Option<u32>,
334}
335
336#[derive(Debug, Clone, Serialize, Deserialize)]
339pub struct SummaryReport {
340 pub window_seconds: i64,
341 pub service_filter: Option<String>,
342 pub traces: TraceSummary,
343 pub top_services: Vec<ServiceSummary>,
344 pub top_error_operations: Vec<ErrorOperation>,
345 pub logs: LogSummary,
346 pub metrics: MetricSummary,
347}
348
349#[derive(Debug, Clone, Default, Serialize, Deserialize)]
350pub struct TraceSummary {
351 pub span_count: i64,
352 pub trace_count: i64,
353 pub error_count: i64,
354 pub error_rate: f64,
355 pub avg_ms: f64,
356 pub max_ms: f64,
357 pub p50_ms: f64,
358 pub p95_ms: f64,
359 pub p99_ms: f64,
360}
361
362#[derive(Debug, Clone, Serialize, Deserialize)]
363pub struct ServiceSummary {
364 pub service: String,
365 pub span_count: i64,
366 pub error_rate: f64,
367 pub p95_ms: f64,
368}
369
370#[derive(Debug, Clone, Serialize, Deserialize)]
371pub struct ErrorOperation {
372 pub service: String,
373 pub operation: String,
374 pub error_count: i64,
375}
376
377#[derive(Debug, Clone, Default, Serialize, Deserialize)]
378pub struct LogSummary {
379 pub total: i64,
380 pub error: i64,
381 pub warn: i64,
382 pub info: i64,
383 pub debug: i64,
384}
385
386#[derive(Debug, Clone, Default, Serialize, Deserialize)]
387pub struct MetricSummary {
388 pub point_count: i64,
389 pub unique_names: i64,
390}
391
392#[derive(Debug, Clone, Serialize, Deserialize)]
395pub struct AnomalyReport {
396 pub current_seconds: i64,
397 pub baseline_seconds: i64,
398 pub service_filter: Option<String>,
399 pub anomalies: Vec<Anomaly>,
400}
401
402#[derive(Debug, Clone, Serialize, Deserialize)]
403pub struct Anomaly {
404 pub service: String,
405 pub kind: String,
406 pub severity: String,
407 pub current: f64,
408 pub baseline: f64,
409 pub delta: f64,
410 pub description: String,
411}
412
413#[derive(Debug, Clone, Serialize, Deserialize)]
416pub struct CorrelateReport {
417 pub trace_id: String,
418 pub span_count: usize,
419 pub services: Vec<String>,
420 pub start_time: String,
421 pub end_time: String,
422 pub duration_ms: f64,
423 pub error_count: i64,
424 pub logs: Vec<LogRecord>,
425 pub metrics: Vec<MetricPoint>,
426}
427
428#[derive(Debug, Clone, Default, Serialize, Deserialize)]
429pub struct LogQuery {
430 pub service: Option<String>,
431 pub severity: Option<String>,
432 pub body_contains: Option<String>,
433 pub trace_id: Option<String>,
434 pub last_seconds: Option<i64>,
435 pub limit: Option<u32>,
436}