Pinned event-mongodb metrics attribution and lag recording boundaries
Parent: Change Data Capture Patterns · Published reference · snapshot 2026-11-02
↓ Facts as markdownall context files
Source-anchored research for Pinned event-mongodb metrics attribution and lag recording boundaries. Run status: COMPLETED.
These notes link each claim to its source. Some citations identify archived research reports that are no longer hosted on this site. A published reference means the content is available; it does not certify independent review or accuracy.Read the editorial policy and follow the sources before relying on a claim.
How it works
- `NewMetrics` registers an observable pending gauge callback that observes the integer returned by the configured pending callback, without measurement attributes, only when that callback is nonnil. `SetPendingCallback` stores the supplied function under a lock. The metric implementation does not query an acknowledgment store itself; its fixture supplies a constant callback and expects the collected value to be `42`. (medium confidence) [source 1] [source 2]
Problems, failure modes and limitations
- In the pinned implementation, `processChange` decodes the stream document and extracts the change event before recording receive lag when `doc.ClusterTime.T > 0`. It records before empty-update filtering, payload construction or rejection, pending storage and channel publication. Consequently, a receive sample need not correspond to a delivered middleware invocation, and a decode failure produces no receive sample. (low confidence) [source]
- `MetricsMiddleware` starts a separate timer immediately before `next(ctx, ev, data)`, records elapsed seconds after that call returns, then records the outcome counter and returns the original handler error. Duration and counters carry event, operation and namespace. The timed boundary is the wrapped `next(ctx, ev, data)` call, including any downstream middleware; it is not a durable acknowledgment or independently verified business-effect completion boundary. (medium confidence) [source 1] [source 2]
- After `next(ctx, ev, data)` returns, `MetricsMiddleware` counts a nil error as processed. For a nonnil error it uses `event.ClassifyError`: `event.ResultAck` increments processed and every other result increments failed. The fixture table expects nil and `event.ErrAck` to count as processed, and `event.ErrNack`, `event.ErrReject`, `event.ErrDefer` and an unknown error to count as failed; a separate fixture asserts that the original handler error is preserved. These are return-classification counters, not acknowledgment-store success counters. (medium confidence) [source 1] [source 2] [source 3]
- The pinned README says subtracting receive lag from oplog lag gives handler queuing plus processing time. The pinned code records oplog lag before `next(ctx, ev, data)`, and times `next(ctx, ev, data)` separately, so that subtraction cannot include that invocation's subsequent execution time. Furthermore, receive samples precede filtering and publication and carry only namespace, while oplog samples require parseable middleware metadata and carry event and namespace. These aggregate histograms do not establish paired-event subtraction. (low confidence) [source 1] [source 2] [source 3]
- For collection, database and cluster watches, the pinned transport records a stream opened only after the selected watch call returns without error, and defers a stream-closed recording with `context.Background()` when the watch function exits. The recording methods add plus one and minus one to the active-stream instrument with namespace. `watchNamespace` joins the database and collection names with a dot for collection watches, appends a dot and wildcard to the database name for database watches, returns "*.*" for cluster watches and "unknown" for an unrecognized level. (medium confidence) [source 1] [source 2]
- In `watchLoop`, a nonnil `watchOnce` error increments reconnections after the parent-context cancellation check, before the backoff wait and the next watch attempt. The reason is history_lost when `isChangeStreamHistoryLost` classifies it that way, otherwise error; `RecordReconnection` adds one with namespace and reason. This counts error-triggered retry paths, and does not prove that a replacement stream opened successfully. (medium confidence) [source 1] [source 2]
- The direct-recording stream fixture calls two opens and one close and expects net active count `1` with namespace. Its reconnection fixture calls error, history_lost and error and expects total `3`, split `2` and `1` by reason. Its receive-lag fixture supplies `1.5`, `0.5` and `-10`, expects sample count `3` and a sum between `1.99` and `2.01`, and checks namespace. These fixtures exercise recording and aggregation through `testMetrics`, which constructs a `sdkmetric.ManualReader`; they do not measure live stream lifecycle or transport lag. (medium confidence) [source 1] [source 2]
Comparisons and alternatives
- `RecordReceiveLag` clamps negative input to zero and records a histogram sample with only `namespace`. Its transport caller passes the extracted change namespace, which `extractChangeEvent` forms from database and collection with transport defaults when available. This is the event namespace, rather than the database or cluster watch wildcard used for active-stream and reconnection metrics. (medium confidence) [source 1] [source 2]
Facts and statements
- Receive lag uses `time.Since(time.Unix(int64(doc.ClusterTime.T), 0)).Seconds()`. `extractChangeEvent` also builds `Timestamp` with zero nanoseconds from that same seconds field, and `buildMetadata` formats it as `time.RFC3339Nano` for `MetadataClusterTime` (`cluster_time`). This formatting does not restore timestamp precision discarded by the seconds-only conversion. (medium confidence) [source 1] [source 2]
- `MetricsMiddleware` obtains the event attribute from `event.ContextName(ctx)` and operation and namespace from context metadata; absent operation or namespace values remain empty strings. It records oplog lag only for nonempty `MetadataClusterTime` that parses with `time.RFC3339Nano`, clamps negative lag to zero, and attaches event and namespace, omitting operation. It records this lag before calling `next(ctx, ev, data)`. (medium confidence) [source 1] [source 2]
- The middleware fixtures use `testMetrics` with a `sdkmetric.ManualReader` and fabricated context metadata. The oplog fixture sets cluster time two seconds in the past, expects one sample and a sum at least `2.0`; the duration fixture sleeps for ten milliseconds inside the wrapped handler and expects one sample and a sum at least `0.01`. The no-metadata fixture expects processed count `1` and no oplog samples. These fixture assertions describe separate synthetic boundaries and do not establish paired-event latency arithmetic or production measurement. (low confidence) [source]
- `WithMetricsNamespace` adds a nonempty namespace followed by an underscore to metric names, whereas namespace measurement attributes come from recording arguments or context metadata. The namespace fixture expects `orders_mongodb_changes_processed_total` and rejects an unprefixed processed metric. A metric-name prefix therefore does not change the source of the namespace attribute. (medium confidence) [source 1] [source 2]
Children
- No children recorded.