Skip to main content

laminar_connectors/mongodb/metrics/
mod.rs

1//! `MongoDB` connector metrics.
2//!
3//! Prometheus-backed counters for tracking CDC source and sink performance.
4
5use prometheus::{IntCounter, IntGauge, Registry};
6
7use super::change_event::ChangeOperation;
8use crate::prom::reg_or_local;
9
10/// Metrics for the `MongoDB` CDC source connector.
11#[derive(Debug, Clone)]
12pub struct MongoDbCdcMetrics {
13    /// Total change events received.
14    pub events_received: IntCounter,
15    /// Total bytes received from the change stream.
16    pub bytes_received: IntCounter,
17    /// Total errors encountered.
18    pub errors: IntCounter,
19    /// Total batches produced for downstream.
20    pub batches_produced: IntCounter,
21    /// Total INSERT operations received.
22    pub inserts: IntCounter,
23    /// Total UPDATE operations received.
24    pub updates: IntCounter,
25    /// Total REPLACE operations received.
26    pub replaces: IntCounter,
27    /// Total DELETE operations received.
28    pub deletes: IntCounter,
29    /// Total lifecycle, metadata, and unrecognized events.
30    pub lifecycle_events: IntCounter,
31    /// Collection-metadata events document mode skipped because they leave documents unchanged.
32    pub metadata_events_skipped: IntCounter,
33    /// Documents copied by the initial snapshot.
34    pub snapshot_documents: IntCounter,
35    /// 1 while emitted progress is inside the initial snapshot copy, 0 once streaming.
36    pub snapshot_in_progress: IntGauge,
37    /// Total reconnection attempts.
38    pub reconnects: IntCounter,
39}
40
41impl MongoDbCdcMetrics {
42    /// Creates a new metrics instance with all counters at zero.
43    #[must_use]
44    #[allow(clippy::missing_panics_doc)]
45    pub fn new(registry: Option<&Registry>) -> Self {
46        let mut local = None;
47        let reg = reg_or_local(registry, &mut local);
48
49        Self {
50            events_received: reg.counter(
51                "mongodb_cdc_events_received_total",
52                "Total MongoDB CDC events received",
53            ),
54            bytes_received: reg.counter(
55                "mongodb_cdc_bytes_received_total",
56                "Total bytes from change stream",
57            ),
58            errors: reg.counter("mongodb_cdc_errors_total", "Total MongoDB CDC errors"),
59            batches_produced: reg.counter(
60                "mongodb_cdc_batches_produced_total",
61                "Total batches produced",
62            ),
63            inserts: reg.counter("mongodb_cdc_inserts_total", "Total INSERT events"),
64            updates: reg.counter("mongodb_cdc_updates_total", "Total UPDATE events"),
65            replaces: reg.counter("mongodb_cdc_replaces_total", "Total REPLACE events"),
66            deletes: reg.counter("mongodb_cdc_deletes_total", "Total DELETE events"),
67            lifecycle_events: reg.counter(
68                "mongodb_cdc_lifecycle_events_total",
69                "Total lifecycle events",
70            ),
71            metadata_events_skipped: reg.counter(
72                "mongodb_cdc_metadata_events_skipped_total",
73                "Collection metadata events skipped by document replication",
74            ),
75            snapshot_documents: reg.counter(
76                "mongodb_cdc_snapshot_documents_total",
77                "Documents emitted by the initial snapshot",
78            ),
79            snapshot_in_progress: reg.gauge(
80                "mongodb_cdc_snapshot_in_progress",
81                "1 while the initial snapshot copy is being emitted",
82            ),
83            reconnects: reg.counter(
84                "mongodb_cdc_reconnects_total",
85                "Total reconnection attempts",
86            ),
87        }
88    }
89
90    /// Records a received change event by operation type.
91    pub fn record_event(&self, operation: ChangeOperation) {
92        self.events_received.inc();
93        match operation {
94            ChangeOperation::Insert => self.inserts.inc(),
95            ChangeOperation::Update => self.updates.inc(),
96            ChangeOperation::Replace => self.replaces.inc(),
97            ChangeOperation::Delete => self.deletes.inc(),
98            ChangeOperation::Invalidate
99            | ChangeOperation::Drop
100            | ChangeOperation::Rename
101            | ChangeOperation::DropDatabase
102            | ChangeOperation::Metadata
103            | ChangeOperation::Unknown => self.lifecycle_events.inc(),
104        }
105    }
106
107    /// Records bytes received from the change stream.
108    pub fn record_bytes(&self, bytes: u64) {
109        self.bytes_received.inc_by(bytes);
110    }
111
112    /// Records an error.
113    pub fn record_error(&self) {
114        self.errors.inc();
115    }
116
117    /// Records a batch produced for downstream.
118    pub fn record_batch(&self) {
119        self.batches_produced.inc();
120    }
121
122    /// Records a reconnection attempt.
123    pub fn record_reconnect(&self) {
124        self.reconnects.inc();
125    }
126}
127
128impl Default for MongoDbCdcMetrics {
129    fn default() -> Self {
130        Self::new(None)
131    }
132}
133
134/// Metrics for the `MongoDB` sink connector.
135#[derive(Debug, Clone)]
136pub struct MongoDbSinkMetrics {
137    /// Total records written.
138    pub records_written: IntCounter,
139    /// Total bytes written.
140    pub bytes_written: IntCounter,
141    /// Total errors encountered.
142    pub errors: IntCounter,
143    /// Total batches flushed.
144    pub batches_flushed: IntCounter,
145    /// Total bulk write operations issued.
146    pub bulk_writes: IntCounter,
147    /// Total individual insert operations.
148    pub inserts: IntCounter,
149    /// Total upsert operations.
150    pub upserts: IntCounter,
151    /// Total delete operations.
152    pub deletes: IntCounter,
153}
154
155impl MongoDbSinkMetrics {
156    /// Creates a new metrics instance with all counters at zero.
157    #[must_use]
158    #[allow(clippy::missing_panics_doc)]
159    pub fn new(registry: Option<&Registry>) -> Self {
160        let mut local = None;
161        let reg = reg_or_local(registry, &mut local);
162
163        Self {
164            records_written: reg.counter(
165                "mongodb_sink_records_written_total",
166                "Total MongoDB sink records written",
167            ),
168            bytes_written: reg.counter(
169                "mongodb_sink_bytes_written_total",
170                "Total MongoDB sink bytes written",
171            ),
172            errors: reg.counter("mongodb_sink_errors_total", "Total MongoDB sink errors"),
173            batches_flushed: reg.counter(
174                "mongodb_sink_batches_flushed_total",
175                "Total batches flushed",
176            ),
177            bulk_writes: reg.counter(
178                "mongodb_sink_bulk_writes_total",
179                "Total bulk write operations",
180            ),
181            inserts: reg.counter("mongodb_sink_inserts_total", "Total insert operations"),
182            upserts: reg.counter("mongodb_sink_upserts_total", "Total upsert operations"),
183            deletes: reg.counter("mongodb_sink_deletes_total", "Total delete operations"),
184        }
185    }
186
187    /// Records a successful batch flush.
188    pub fn record_flush(&self, records: u64, bytes: u64) {
189        self.records_written.inc_by(records);
190        self.bytes_written.inc_by(bytes);
191        self.batches_flushed.inc();
192    }
193
194    /// Records a bulk write operation.
195    pub fn record_bulk_write(&self) {
196        self.bulk_writes.inc();
197    }
198
199    /// Records an error.
200    pub fn record_error(&self) {
201        self.errors.inc();
202    }
203
204    /// Records insert operations.
205    pub fn record_inserts(&self, count: u64) {
206        self.inserts.inc_by(count);
207    }
208
209    /// Records upsert operations.
210    pub fn record_upserts(&self, count: u64) {
211        self.upserts.inc_by(count);
212    }
213
214    /// Records delete operations.
215    pub fn record_deletes(&self, count: u64) {
216        self.deletes.inc_by(count);
217    }
218}
219
220impl Default for MongoDbSinkMetrics {
221    fn default() -> Self {
222        Self::new(None)
223    }
224}
225
226#[cfg(test)]
227mod tests;