use crate::event::context::StageType;
use crate::event::observability::{
EdgeLivenessState, HttpPullMetricsSnapshot, HttpSurfaceRouteMetricsSnapshot, MeasurementWindow,
StageActivity,
};
use crate::event::payloads::system_payload::{
ContractName, ContractResultStatusLabel, SystemFeedRole,
};
use crate::event::status::processing_status::ErrorKind;
use crate::event::types::EventType;
use crate::event::SinkOperationPhase;
use crate::id::{FlowId, StageId};
use crate::ingress::IngressKey;
use crate::metrics::composite::{
CompositeContract, CompositeDurationHistogram, CompositeDurationInvalid, CompositeMemberHealth,
CompositePortTraffic,
};
use crate::metrics::Percentile;
use crate::time::MetricsDuration;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct AppMetricsSnapshot {
#[serde(default)]
pub throughput: super::ThroughputSnapshot,
#[serde(default)]
pub observation_export_interval: Option<std::time::Duration>,
pub timestamp: chrono::DateTime<chrono::Utc>,
pub event_counts: HashMap<StageId, u64>,
pub events_accumulated_total: HashMap<StageId, u64>,
pub events_emitted_total: HashMap<StageId, u64>,
pub join_reference_since_last_stream: HashMap<StageId, u64>,
pub error_counts: HashMap<StageId, u64>,
pub error_counts_by_kind: HashMap<StageId, HashMap<ErrorKind, u64>>,
pub sink_operation_failures: Vec<SinkOperationFailureMetric>,
pub processing_times: HashMap<StageId, HistogramSnapshot>,
pub in_flight: HashMap<StageId, f64>,
pub cpu_usage_ratio: HashMap<StageId, f64>,
pub memory_bytes: HashMap<StageId, f64>,
pub anomalies_total: HashMap<StageId, u64>,
pub amendments_total: HashMap<StageId, u64>,
pub saturation_ratio: HashMap<StageId, f64>,
pub failures_total: HashMap<StageId, u64>,
pub event_loops_total: HashMap<StageId, u64>,
pub event_loops_with_work_total: HashMap<StageId, u64>,
pub flow_latency_seconds: HashMap<StageId, HistogramSnapshot>,
pub dropped_events: HashMap<StageId, f64>,
pub circuit_breaker_state: HashMap<StageId, f64>,
pub circuit_breaker_rejection_rate: HashMap<StageId, f64>,
pub circuit_breaker_consecutive_failures: HashMap<StageId, f64>,
pub circuit_breaker_requests_total: HashMap<StageId, u64>,
pub circuit_breaker_rejections_total: HashMap<StageId, u64>,
pub circuit_breaker_opened_total: HashMap<StageId, u64>,
pub circuit_breaker_successes_total: HashMap<StageId, u64>,
pub circuit_breaker_failures_total: HashMap<StageId, u64>,
pub circuit_breaker_slow_total: HashMap<StageId, u64>,
pub circuit_breaker_time_in_state_seconds_total: HashMap<(StageId, String), f64>,
pub circuit_breaker_state_transitions_total: HashMap<(StageId, String, String), u64>,
pub rate_limiter_utilization: HashMap<StageId, f64>,
pub rate_limiter_events_total: HashMap<StageId, u64>,
pub rate_limiter_delayed_total: HashMap<StageId, u64>,
pub rate_limiter_tokens_consumed_total: HashMap<StageId, f64>,
pub rate_limiter_delay_seconds_total: HashMap<StageId, f64>,
pub rate_limiter_bucket_tokens: HashMap<StageId, f64>,
pub rate_limiter_bucket_capacity: HashMap<StageId, f64>,
pub backpressure_window: HashMap<(StageId, StageId), u64>,
pub backpressure_in_flight: HashMap<(StageId, StageId), u64>,
pub backpressure_credits: HashMap<(StageId, StageId), u64>,
pub backpressure_blocked: HashMap<StageId, f64>,
pub backpressure_bypass_enabled: bool,
pub backpressure_min_reader_seq: HashMap<StageId, u64>,
pub backpressure_writer_seq: HashMap<StageId, u64>,
pub backpressure_wait_seconds_total: HashMap<StageId, f64>,
pub edge_liveness_state: HashMap<(StageId, StageId), EdgeLivenessState>,
pub contract_metrics: ContractMetricsSnapshot,
pub http_surface_metrics: Vec<HttpSurfaceRouteMetricsSnapshot>,
pub ingestion_refusal_totals: HashMap<(IngressKey, String), u64>,
pub http_pull_metrics: HashMap<StageId, HttpPullMetricsSnapshot>,
pub ai_chunking_metrics: HashMap<StageId, AiChunkingMetricsSnapshot>,
pub flow_metrics: Option<FlowMetricsSnapshot>,
pub stage_metadata: HashMap<StageId, StageMetadata>,
pub stage_first_event_time: HashMap<StageId, chrono::DateTime<chrono::Utc>>,
pub stage_last_event_time: HashMap<StageId, chrono::DateTime<chrono::Utc>>,
pub stage_lifecycle_states: HashMap<(StageId, String), bool>,
pub pipeline_state: String,
pub stage_vector_clocks: HashMap<StageId, u64>,
pub composite_port_traffic: Vec<CompositePortTraffic>,
pub composite_member_health: Vec<CompositeMemberHealth>,
pub composite_boundary_durations: Vec<CompositeDurationHistogram>,
pub composite_boundary_duration_invalid: Vec<CompositeDurationInvalid>,
pub composite_contracts: Vec<CompositeContract>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SinkOperationFailureMetric {
pub stage_id: StageId,
pub phase: SinkOperationPhase,
pub error_kind: ErrorKind,
pub count: u64,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ContractMetricEdgeKey {
pub upstream: StageId,
pub downstream: StageId,
pub contract: ContractName,
#[serde(skip_serializing_if = "Option::is_none")]
pub selected_event_type: Option<EventType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub feed_role: Option<SystemFeedRole>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ContractMetricResultKey {
pub edge: ContractMetricEdgeKey,
pub status: ContractResultStatusLabel,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ContractViolationCauseLabel(String);
impl ContractViolationCauseLabel {
pub fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for ContractViolationCauseLabel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
impl From<&str> for ContractViolationCauseLabel {
fn from(value: &str) -> Self {
Self::new(value)
}
}
impl From<String> for ContractViolationCauseLabel {
fn from(value: String) -> Self {
Self::new(value)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ContractMetricViolationKey {
pub edge: ContractMetricEdgeKey,
pub cause: ContractViolationCauseLabel,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ContractMetricsSnapshot {
pub results_total: HashMap<ContractMetricResultKey, u64>,
pub violations_total: HashMap<ContractMetricViolationKey, u64>,
pub reader_seq: HashMap<ContractMetricEdgeKey, u64>,
pub advertised_writer_seq: HashMap<ContractMetricEdgeKey, u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InfraMetricsSnapshot {
pub timestamp: chrono::DateTime<chrono::Utc>,
pub journal_metrics: JournalMetricsSnapshot,
pub stage_metrics: HashMap<StageId, StageInfraMetrics>,
pub liveness_metrics: LivenessMetricsSnapshot,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct LivenessMetricsSnapshot {
pub stage_handler_blocked_seconds: HashMap<StageId, f64>,
pub stage_activity: HashMap<StageId, StageActivity>,
pub edge_idle_seconds: HashMap<(StageId, StageId), f64>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AiChunkingMetricsSnapshot {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub jobs_total: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub input_items_total: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub planned_items_total: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub excluded_items_total: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub chunks_emitted_total: Option<u64>,
pub rerender_attempts_total: Option<u64>,
pub max_depth_reached: Option<u32>,
pub budget_overhead_tokens: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HistogramSnapshot {
pub count: u64,
pub sum: f64,
pub min: f64,
pub max: f64,
pub percentiles: HashMap<Percentile, f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FlowMetricsSnapshot {
pub flow_duration: MetricsDuration,
pub total_events_processed: u64,
pub events_in: u64,
pub events_out: u64,
pub errors_total: u64,
pub event_loops_total: Option<u64>,
pub event_loops_with_work_total: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StageMetricsSnapshot {
pub processing_time_count: Option<u64>,
pub timing_window: Option<MeasurementWindow>,
pub events_processed_total: u64,
#[serde(default)]
pub events_accumulated_total: u64,
#[serde(default)]
pub events_emitted_total: u64,
pub errors_total: u64,
pub errors_by_kind:
std::collections::HashMap<crate::event::status::processing_status::ErrorKind, u64>,
pub in_flight: Option<u32>,
pub recent_p50_ms: Option<u64>,
pub recent_p90_ms: Option<u64>,
pub recent_p95_ms: Option<u64>,
pub recent_p99_ms: Option<u64>,
pub recent_p999_ms: Option<u64>,
#[serde(default)]
pub processing_time_sum_nanos: Option<u64>,
pub event_loops_total: Option<u64>,
pub event_loops_with_work_total: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FlowLifecycleMetricsSnapshot {
pub events_in_total: u64,
pub events_out_total: u64,
pub errors_total: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JournalMetricsSnapshot {
pub writes_total: u64,
pub write_latency: HistogramSnapshot,
pub throughput: f64,
pub bytes_written: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StageInfraMetrics {
pub in_flight: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StageMetadata {
pub name: String,
pub stage_type: StageType,
#[serde(skip_serializing_if = "Option::is_none")]
pub reference_mode: Option<String>,
pub flow_name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub flow_id: Option<FlowId>,
}
impl Default for AppMetricsSnapshot {
fn default() -> Self {
Self {
throughput: Default::default(),
observation_export_interval: None,
timestamp: chrono::Utc::now(),
event_counts: HashMap::new(),
events_accumulated_total: HashMap::new(),
events_emitted_total: HashMap::new(),
join_reference_since_last_stream: HashMap::new(),
error_counts: HashMap::new(),
error_counts_by_kind: HashMap::new(),
sink_operation_failures: Vec::new(),
processing_times: HashMap::new(),
in_flight: HashMap::new(),
cpu_usage_ratio: HashMap::new(),
memory_bytes: HashMap::new(),
anomalies_total: HashMap::new(),
amendments_total: HashMap::new(),
saturation_ratio: HashMap::new(),
failures_total: HashMap::new(),
event_loops_total: HashMap::new(),
event_loops_with_work_total: HashMap::new(),
flow_latency_seconds: HashMap::new(),
dropped_events: HashMap::new(),
circuit_breaker_state: HashMap::new(),
circuit_breaker_rejection_rate: HashMap::new(),
circuit_breaker_consecutive_failures: HashMap::new(),
circuit_breaker_requests_total: HashMap::new(),
circuit_breaker_rejections_total: HashMap::new(),
circuit_breaker_opened_total: HashMap::new(),
circuit_breaker_successes_total: HashMap::new(),
circuit_breaker_failures_total: HashMap::new(),
circuit_breaker_slow_total: HashMap::new(),
circuit_breaker_time_in_state_seconds_total: HashMap::new(),
circuit_breaker_state_transitions_total: HashMap::new(),
rate_limiter_utilization: HashMap::new(),
rate_limiter_events_total: HashMap::new(),
rate_limiter_delayed_total: HashMap::new(),
rate_limiter_tokens_consumed_total: HashMap::new(),
rate_limiter_delay_seconds_total: HashMap::new(),
rate_limiter_bucket_tokens: HashMap::new(),
rate_limiter_bucket_capacity: HashMap::new(),
backpressure_window: HashMap::new(),
backpressure_in_flight: HashMap::new(),
backpressure_credits: HashMap::new(),
backpressure_blocked: HashMap::new(),
backpressure_bypass_enabled: false,
backpressure_min_reader_seq: HashMap::new(),
backpressure_writer_seq: HashMap::new(),
backpressure_wait_seconds_total: HashMap::new(),
edge_liveness_state: HashMap::new(),
contract_metrics: ContractMetricsSnapshot::default(),
http_surface_metrics: Vec::new(),
ingestion_refusal_totals: HashMap::new(),
http_pull_metrics: HashMap::new(),
ai_chunking_metrics: HashMap::new(),
flow_metrics: None,
stage_metadata: HashMap::new(),
stage_first_event_time: HashMap::new(),
stage_last_event_time: HashMap::new(),
stage_lifecycle_states: HashMap::new(),
pipeline_state: String::new(),
stage_vector_clocks: HashMap::new(),
composite_port_traffic: Vec::new(),
composite_member_health: Vec::new(),
composite_boundary_durations: Vec::new(),
composite_boundary_duration_invalid: Vec::new(),
composite_contracts: Vec::new(),
}
}
}
impl Default for InfraMetricsSnapshot {
fn default() -> Self {
Self {
timestamp: chrono::Utc::now(),
journal_metrics: JournalMetricsSnapshot::default(),
stage_metrics: HashMap::new(),
liveness_metrics: LivenessMetricsSnapshot::default(),
}
}
}
impl Default for HistogramSnapshot {
fn default() -> Self {
Self {
count: 0,
sum: 0.0,
min: f64::INFINITY,
max: f64::NEG_INFINITY,
percentiles: HashMap::new(),
}
}
}
impl Default for JournalMetricsSnapshot {
fn default() -> Self {
Self {
writes_total: 0,
write_latency: HistogramSnapshot::default(),
throughput: 0.0,
bytes_written: 0,
}
}
}