Skip to content

Commit 5542080

Browse files
committed
Refactor metrics to event-based streaming with operation IDs
1 parent ebb94a6 commit 5542080

4 files changed

Lines changed: 148 additions & 76 deletions

File tree

kernel/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ pub trait Engine: AsAny {
713713

714714
/// Get the connector provided [`metrics::MetricsReporter`] for metrics collection.
715715
///
716-
/// Returns an optional reporter that will be notified of metrics from Delta operations.
716+
/// Returns an optional reporter that will receive metric events from Delta operations.
717717
/// The default implementation returns None (no metrics reporting).
718718
fn get_metrics_reporter(&self) -> Option<Arc<dyn crate::metrics::MetricsReporter>> {
719719
None

kernel/src/metrics/mod.rs

Lines changed: 66 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,37 @@
22
//!
33
//! This module provides metrics tracking for various Delta operations including
44
//! snapshot creation, scans, and transactions. Metrics are collected during operations
5-
//! and can be reported via the `MetricsReporter` trait.
5+
//! and reported as events via the `MetricsReporter` trait.
6+
//!
7+
//! Each operation (Snapshot, Transaction, Scan) is assigned a unique operation ID (UUID)
8+
//! when it starts, and all subsequent events for that operation reference this ID.
9+
//! This allows reporters to correlate events and track operation lifecycles.
610
//!
711
//! # Example: Implementing a Custom MetricsReporter
812
//!
913
//! ```
1014
//! use std::sync::Arc;
11-
//! use delta_kernel::metrics::{MetricsReporter, SnapshotMetrics};
15+
//! use delta_kernel::metrics::{MetricsReporter, MetricEvent};
1216
//!
1317
//! struct LoggingReporter;
1418
//!
1519
//! impl MetricsReporter for LoggingReporter {
16-
//! fn report_snapshot(&self, metrics: &SnapshotMetrics) {
17-
//! println!("Snapshot creation took {:?}", metrics.load_snapshot_total_duration);
18-
//! println!(" - Protocol/Metadata load: {:?}", metrics.load_protocol_metadata_duration);
19-
//! println!(" - Log segment load: {:?}", metrics.load_log_segment_duration);
20-
//! println!(" - Files: {} commits, {} checkpoints, {} compactions",
21-
//! metrics.num_commit_files,
22-
//! metrics.num_checkpoint_files,
23-
//! metrics.num_compaction_files);
20+
//! fn report(&self, event: MetricEvent) {
21+
//! match event {
22+
//! MetricEvent::SnapshotStarted { operation_id, table_path } => {
23+
//! println!("Snapshot started: {} for table {}", operation_id, table_path);
24+
//! }
25+
//! MetricEvent::LogSegmentLoaded { operation_id, duration, num_commit_files, .. } => {
26+
//! println!(" Log segment loaded in {:?}: {} commits", duration, num_commit_files);
27+
//! }
28+
//! MetricEvent::SnapshotCompleted { operation_id, version, total_duration } => {
29+
//! println!("Snapshot completed: v{} in {:?}", version, total_duration);
30+
//! }
31+
//! MetricEvent::SnapshotFailed { operation_id } => {
32+
//! println!("Snapshot failed: {}", operation_id);
33+
//! }
34+
//! _ => {}
35+
//! }
2436
//! }
2537
//! }
2638
//! ```
@@ -31,62 +43,79 @@
3143
//!
3244
//! ```
3345
//! use std::sync::Arc;
34-
//! use delta_kernel::metrics::{MetricsReporter, SnapshotMetrics};
46+
//! use delta_kernel::metrics::{MetricsReporter, MetricEvent};
3547
//!
3648
//! struct CompositeReporter {
3749
//! reporters: Vec<Arc<dyn MetricsReporter>>,
3850
//! }
3951
//!
4052
//! impl MetricsReporter for CompositeReporter {
41-
//! fn report_snapshot(&self, metrics: &SnapshotMetrics) {
53+
//! fn report(&self, event: MetricEvent) {
4254
//! for reporter in &self.reporters {
43-
//! reporter.report_snapshot(metrics);
55+
//! reporter.report(event.clone());
4456
//! }
4557
//! }
4658
//! }
4759
//! ```
4860
4961
use std::time::{Duration, Instant};
62+
use uuid::Uuid;
5063

51-
/// Trait for reporting metrics from Delta operations.
64+
/// Trait for reporting metrics events from Delta operations.
5265
///
53-
/// Implementations of this trait receive metrics after operations complete
66+
/// Implementations of this trait receive metric events as they occur during operations
5467
/// and can forward them to monitoring systems like Prometheus, DataDog, etc.
68+
///
69+
/// Events are emitted throughout an operation's lifecycle, allowing real-time monitoring.
5570
pub trait MetricsReporter: Send + Sync {
56-
/// Report snapshot creation metrics.
57-
fn report_snapshot(&self, metrics: &SnapshotMetrics);
71+
/// Report a metric event.
72+
fn report(&self, event: MetricEvent);
5873
}
5974

60-
/// Metrics collected during snapshot creation.
75+
/// Metric events emitted during Delta Kernel operations.
6176
///
62-
/// These metrics track the time spent in various phases of loading a snapshot,
63-
/// including log segment construction and protocol/metadata loading.
64-
/// They also track counts of files processed during snapshot creation.
65-
#[derive(Debug, Clone, Default)]
66-
pub struct SnapshotMetrics {
67-
/// Total time spent loading the snapshot (all operations combined).
68-
pub load_snapshot_total_duration: Duration,
77+
/// Each event includes an `operation_id` (UUID) that uniquely identifies the operation
78+
/// instance. This allows correlating multiple events from the same operation.
79+
#[derive(Debug, Clone)]
80+
pub enum MetricEvent {
81+
/// A snapshot creation operation has started.
82+
SnapshotStarted {
83+
operation_id: Uuid,
84+
table_path: String,
85+
},
6986

70-
/// Time spent loading protocol and metadata actions.
71-
pub load_protocol_metadata_duration: Duration,
87+
/// Log segment loading completed (listing and organizing log files).
88+
LogSegmentLoaded {
89+
operation_id: Uuid,
90+
duration: Duration,
91+
num_commit_files: u64,
92+
num_checkpoint_files: u64,
93+
num_compaction_files: u64,
94+
},
7295

73-
/// Time spent building the log segment (listing and organizing log files).
74-
pub load_log_segment_duration: Duration,
96+
/// Protocol and metadata loading completed.
97+
ProtocolMetadataLoaded {
98+
operation_id: Uuid,
99+
duration: Duration,
100+
},
75101

76-
/// Number of commit files processed during snapshot creation.
77-
pub num_commit_files: u64,
102+
/// Snapshot creation completed successfully.
103+
SnapshotCompleted {
104+
operation_id: Uuid,
105+
version: u64,
106+
total_duration: Duration,
107+
},
78108

79-
/// Number of checkpoint files processed during snapshot creation.
80-
pub num_checkpoint_files: u64,
81-
82-
/// Number of compaction files processed during snapshot creation.
83-
pub num_compaction_files: u64,
109+
/// Snapshot creation failed.
110+
SnapshotFailed { operation_id: Uuid },
84111
}
85112

86113
/// A simple timer for tracking operation durations.
87114
///
88115
/// # Example
89-
/// ```ignore
116+
/// ```
117+
/// use delta_kernel::metrics::Timer;
118+
///
90119
/// let timer = Timer::new();
91120
/// // ... do work ...
92121
/// let duration = timer.elapsed();

kernel/src/snapshot.rs

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::checkpoint::CheckpointWriter;
1111
use crate::committer::Committer;
1212
use crate::listed_log_files::ListedLogFiles;
1313
use crate::log_segment::LogSegment;
14-
use crate::metrics::{SnapshotMetrics, Timer};
14+
use crate::metrics::{MetricEvent, Timer};
1515
use crate::path::ParsedLogPath;
1616
use crate::scan::ScanBuilder;
1717
use crate::schema::SchemaRef;
@@ -21,6 +21,7 @@ use crate::transaction::Transaction;
2121
use crate::LogCompactionWriter;
2222
use crate::{DeltaResult, Engine, Error, Version};
2323
use delta_kernel_derive::internal_api;
24+
use uuid::Uuid;
2425

2526
mod builder;
2627
pub use builder::SnapshotBuilder;
@@ -255,51 +256,61 @@ impl Snapshot {
255256
log_segment: LogSegment,
256257
engine: &dyn Engine,
257258
) -> DeltaResult<Self> {
258-
Self::try_new_from_log_segment_with_metrics(
259-
location,
260-
log_segment,
261-
engine,
262-
std::time::Duration::default(),
263-
)
259+
Self::try_new_from_log_segment_with_metrics(location, log_segment, engine, None)
264260
}
265261

266262
pub(crate) fn try_new_from_log_segment_with_metrics(
267263
location: Url,
268264
log_segment: LogSegment,
269265
engine: &dyn Engine,
270-
load_log_segment_duration: std::time::Duration,
266+
operation_id: Option<Uuid>,
271267
) -> DeltaResult<Self> {
268+
let operation_id = operation_id.unwrap_or_else(Uuid::new_v4);
269+
let reporter = engine.get_metrics_reporter();
272270
let timer = Timer::new();
273271

274-
let (metadata, protocol) = log_segment.read_metadata(engine)?;
275-
let load_protocol_metadata_duration = timer.elapsed();
276-
277-
let table_configuration =
278-
TableConfiguration::try_new(metadata, protocol, location, log_segment.end_version)?;
272+
let result = (|| {
273+
let (metadata, protocol) = log_segment.read_metadata(engine)?;
274+
let protocol_metadata_duration = timer.elapsed();
279275

280-
let num_commit_files = log_segment.ascending_commit_files.len() as u64;
281-
let num_checkpoint_files = log_segment.checkpoint_parts.len() as u64;
282-
let num_compaction_files = log_segment.ascending_compaction_files.len() as u64;
283-
284-
let load_snapshot_total_duration = timer.elapsed();
276+
if let Some(ref r) = reporter {
277+
r.report(MetricEvent::ProtocolMetadataLoaded {
278+
operation_id,
279+
duration: protocol_metadata_duration,
280+
});
281+
}
285282

286-
let metrics = SnapshotMetrics {
287-
load_snapshot_total_duration,
288-
load_protocol_metadata_duration,
289-
load_log_segment_duration,
290-
num_commit_files,
291-
num_checkpoint_files,
292-
num_compaction_files,
293-
};
283+
let table_configuration = TableConfiguration::try_new(
284+
metadata,
285+
protocol,
286+
location,
287+
log_segment.end_version,
288+
)?;
294289

295-
if let Some(reporter) = engine.get_metrics_reporter() {
296-
reporter.report_snapshot(&metrics);
290+
Ok(Self {
291+
log_segment,
292+
table_configuration,
293+
})
294+
})();
295+
296+
match result {
297+
Ok(snapshot) => {
298+
if let Some(ref r) = reporter {
299+
r.report(MetricEvent::SnapshotCompleted {
300+
operation_id,
301+
version: snapshot.version(),
302+
total_duration: timer.elapsed(),
303+
});
304+
}
305+
Ok(snapshot)
306+
}
307+
Err(e) => {
308+
if let Some(ref r) = reporter {
309+
r.report(MetricEvent::SnapshotFailed { operation_id });
310+
}
311+
Err(e)
312+
}
297313
}
298-
299-
Ok(Self {
300-
log_segment,
301-
table_configuration,
302-
})
303314
}
304315

305316
/// Creates a [`CheckpointWriter`] for generating a checkpoint from this snapshot.

kernel/src/snapshot/builder.rs

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
//! Builder for creating [`Snapshot`] instances.
22
use crate::log_path::LogPath;
33
use crate::log_segment::LogSegment;
4-
use crate::metrics::Timer;
4+
use crate::metrics::{MetricEvent, Timer};
55
use crate::snapshot::SnapshotRef;
66
use crate::{DeltaResult, Engine, Error, Snapshot, Version};
7+
use uuid::Uuid;
78

89
use url::Url;
910

@@ -84,20 +85,51 @@ impl SnapshotBuilder {
8485
pub fn build(self, engine: &dyn Engine) -> DeltaResult<SnapshotRef> {
8586
let log_tail = self.log_tail.into_iter().map(Into::into).collect();
8687
if let Some(table_root) = self.table_root {
88+
let operation_id = Uuid::new_v4();
89+
let reporter = engine.get_metrics_reporter();
90+
91+
if let Some(ref r) = reporter {
92+
r.report(MetricEvent::SnapshotStarted {
93+
operation_id,
94+
table_path: table_root.to_string(),
95+
});
96+
}
97+
8798
let timer = Timer::new();
88-
let log_segment = LogSegment::for_snapshot(
99+
let log_segment_result = LogSegment::for_snapshot(
89100
engine.storage_handler().as_ref(),
90101
table_root.join("_delta_log/")?,
91102
log_tail,
92103
self.version,
93-
)?;
94-
let load_log_segment_duration = timer.elapsed();
104+
);
105+
106+
let log_segment = match log_segment_result {
107+
Ok(seg) => {
108+
let duration = timer.elapsed();
109+
if let Some(ref r) = reporter {
110+
r.report(MetricEvent::LogSegmentLoaded {
111+
operation_id,
112+
duration,
113+
num_commit_files: seg.ascending_commit_files.len() as u64,
114+
num_checkpoint_files: seg.checkpoint_parts.len() as u64,
115+
num_compaction_files: seg.ascending_compaction_files.len() as u64,
116+
});
117+
}
118+
seg
119+
}
120+
Err(e) => {
121+
if let Some(ref r) = reporter {
122+
r.report(MetricEvent::SnapshotFailed { operation_id });
123+
}
124+
return Err(e);
125+
}
126+
};
95127

96128
Ok(Snapshot::try_new_from_log_segment_with_metrics(
97129
table_root,
98130
log_segment,
99131
engine,
100-
load_log_segment_duration,
132+
Some(operation_id),
101133
)?
102134
.into())
103135
} else {

0 commit comments

Comments
 (0)