use std::{collections::BTreeMap, fmt, sync::Arc};
use query_planning::correlation::{QueryId, TraceId};
use super::{
CleanupFailureSummary, ObservationSequence, PlanExecutionId, QueryAttemptReport, QueryBoundaryKind,
RuntimeObservationClassLoss, RuntimeObservationClock, RuntimeObservationFooter, RuntimeObservationLimits,
RuntimeObservationLossReason, RuntimeObservationManifest, RuntimeObservationPayload, RuntimeObservationReasonLoss,
RuntimeObservationRecordClass, RuntimeSourceLocationId, RuntimeSpanId, RuntimeTerminalOutcome,
RuntimeTimelineEvent, RuntimeTopologyRecord, SystemRuntimeObservationClock,
metrics_summary::{
MetricsCaptureMode, MetricsCompleteness, QueryMetricsCheckpoint, QueryMetricsSummary, SourceReadFact,
},
};
use crate::{
metrics::{QueryMetrics, SourceReadRuntimeMetrics},
observability::{ExecutionProgress, RUNTIME_OBSERVATION_JSONL_SCHEMA, RuntimeClockDomain},
};
mod digest;
mod handle;
mod owner;
mod session;
mod state;
#[cfg(any(test, feature = "test-hooks"))]
use digest::TestSourceLocationDigestKeyProvider;
use digest::{
OsSourceLocationDigestKeyProvider, SourceLocationDigestKeyProvider, SourceLocationDigestKeyState,
SourceLocationDigestKeyUnavailable,
};
#[cfg(test)]
pub(crate) use owner::RuntimeObservationDeliveryGate;
use owner::RuntimeObservationDeliveryGuard;
pub use owner::RuntimeObservationOwner;
pub(crate) use owner::in_runtime_observation_delivery;
#[cfg(any(test, feature = "test-hooks"))]
pub(crate) use session::AttemptReportProvider;
pub use session::RuntimeObservationSession;
pub(crate) use session::{AttemptReportSealProvider, QueryCleanupSealDelivery};
use session::{DeferredRuntimeObservationSeal, RuntimeObservationSealObserver, RuntimeObservationSessionInner};
pub use state::BudgetWindowPeaks;
pub(crate) use state::{BudgetWindow, CleanupFailureTally};
use state::{PlanExecutionMetrics, RuntimeObservationRecorderState};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RuntimeObservationConfig {
enabled: bool,
limits: RuntimeObservationLimits,
}
impl RuntimeObservationConfig {
pub const NATIVE_EXECUTION_MAX_RECORDS: u64 = 65_536;
pub const NATIVE_EXECUTION_MAX_BYTES: u64 = 8 * 1024 * 1024;
pub const fn disabled() -> Self {
Self { enabled: false, limits: RuntimeObservationLimits { max_retained_records: 0, max_retained_bytes: 0 } }
}
pub const fn bounded(max_retained_records: u64, max_retained_bytes: u64) -> Self {
Self { enabled: true, limits: RuntimeObservationLimits { max_retained_records, max_retained_bytes } }
}
pub const fn native_execution() -> Self {
Self::bounded(Self::NATIVE_EXECUTION_MAX_RECORDS, Self::NATIVE_EXECUTION_MAX_BYTES)
}
pub(crate) const fn is_enabled(self) -> bool {
self.enabled
}
pub const fn limits(self) -> RuntimeObservationLimits {
self.limits
}
}
impl Default for RuntimeObservationConfig {
fn default() -> Self {
Self::disabled()
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct RuntimeEventContext {
pub(crate) plan_execution_id: Option<PlanExecutionId>,
pub(crate) span_id: Option<RuntimeSpanId>,
pub(crate) parent_span_id: Option<RuntimeSpanId>,
}
impl RuntimeEventContext {
pub fn for_plan(plan_execution_id: PlanExecutionId) -> Self {
Self { plan_execution_id: Some(plan_execution_id), ..Self::default() }
}
pub const fn with_span(mut self, span_id: RuntimeSpanId, parent_span_id: Option<RuntimeSpanId>) -> Self {
self.span_id = Some(span_id);
self.parent_span_id = parent_span_id;
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RuntimeObservationRecordDisposition {
Disabled,
Retained { sequence: ObservationSequence, logical_bytes: u64 },
Dropped { sequence: ObservationSequence, reason: RuntimeObservationLossReason },
Sealed,
}
#[derive(Debug, Clone)]
pub struct LiveRuntimeObservationSnapshot {
data: Arc<RuntimeObservationSnapshotData>,
}
#[derive(Debug, Clone)]
pub struct SealedRuntimeObservationSnapshot {
data: Arc<RuntimeObservationSnapshotData>,
}
#[derive(Debug, Clone)]
pub(crate) struct RuntimeObservationSnapshotData {
pub(crate) manifest: RuntimeObservationManifest,
pub(crate) topology: Vec<RetainedTopologyRecord>,
pub(crate) events: Vec<RuntimeTimelineEvent>,
pub(crate) footer: RuntimeObservationFooter,
pub(crate) plans: BTreeMap<PlanExecutionId, QueryMetrics>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct RetainedTopologyRecord {
pub(crate) sequence: ObservationSequence,
pub(crate) record: RuntimeTopologyRecord,
}
macro_rules! snapshot_accessors {
($snapshot:ident) => {
impl $snapshot {
pub fn manifest(&self) -> &RuntimeObservationManifest {
&self.data.manifest
}
pub fn topology(&self) -> impl ExactSizeIterator<Item = &RuntimeTopologyRecord> {
self.data.topology.iter().map(|record| &record.record)
}
pub fn events(&self) -> &[RuntimeTimelineEvent] {
&self.data.events
}
pub fn footer(&self) -> &RuntimeObservationFooter {
&self.data.footer
}
pub fn attempt_report(&self) -> Option<&QueryAttemptReport> {
self.data.footer.attempt_report.as_deref()
}
}
};
}
snapshot_accessors!(LiveRuntimeObservationSnapshot);
snapshot_accessors!(SealedRuntimeObservationSnapshot);
impl SealedRuntimeObservationSnapshot {
pub(crate) fn data(&self) -> &RuntimeObservationSnapshotData {
&self.data
}
pub fn query_metrics(&self, plan: &PlanExecutionId) -> Option<&QueryMetrics> {
self.data.plans.get(plan)
}
#[cfg(test)]
pub(crate) fn is_same_snapshot(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.data, &other.data)
}
}
#[derive(Clone, Default)]
pub struct RuntimeObservationHandle {
config: RuntimeObservationConfig,
inner: Option<Arc<RuntimeObservationSessionInner>>,
}
impl fmt::Debug for RuntimeObservationHandle {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("RuntimeObservationHandle")
.field("enabled", &self.is_enabled())
.field("limits", &self.config.limits())
.finish_non_exhaustive()
}
}
#[cfg(test)]
mod tests;