use std::collections::BTreeMap; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; use crate::{RequestId, ScriptId}; /// One row in the `execution_logs` table. Same shape flows through the /// `ExecutionLogSink` trait and the `GET /scripts/{id}/logs` response. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ExecutionLog { pub id: Uuid, pub script_id: ScriptId, pub request_id: RequestId, pub request_path: String, pub request_headers: BTreeMap, pub request_body: serde_json::Value, pub response_code: Option, pub response_body: Option, /// `log::*` entries captured during the execution, serialized as a /// JSON array of `{timestamp, level, message, data}` objects. pub script_logs: serde_json::Value, pub duration_ms: u64, pub status: ExecutionStatus, pub created_at: DateTime, } /// Matches the CHECK constraint on `execution_logs.status`. Keep the /// serde rename in sync with the migration. #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum ExecutionStatus { Success, Error, Timeout, BudgetExceeded, } impl ExecutionStatus { #[must_use] pub fn as_str(self) -> &'static str { match self { Self::Success => "success", Self::Error => "error", Self::Timeout => "timeout", Self::BudgetExceeded => "budget_exceeded", } } }