feat(aggregate transform): Add support for event timestamp-based aggregation - #24421
feat(aggregate transform): Add support for event timestamp-based aggregation#24421kaarolch wants to merge 68 commits into
Conversation
Resolves conflict in src/transforms/aggregate.rs by integrating upstream's InnerMode refactor (prev_map/multi_map moved into enum variants) with the event-time aggregation feature (TimeSource, event_time_buckets, watermark-based flushing). Made-with: Cursor
|
I've added more test around event based timestamp. |
|
@pront I saw you were active in the related issue Can you look on above PR? |
|
Is there any recommendation for this PR, I know PR has 1,2k new lines but it's hard to split them to smaller changes. |
|
@kaarolch — heads up, while running this PR's build in production we hit a memory leak in Production impact we measured: ~140 MB/hour of growth per pod with I drafted a fix that scopes both the insert and the retain to PR is here: kaarolch#1 — opened against your
|
|
@codex review |
Hey @kaarolch, we have a pretty big backlog. So large PRs take even longer to be review and approved. I kicked off a codex review for now, please fix any issues that may arise there. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8574e57ba1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Addresses several bugs surfaced during review of the event-time aggregation feature: * Stop populating `event_time_prev_buckets` in non-`Diff` modes. The map is read only by `Diff` and was previously inserted (and not evicted) on every flush in `Auto`/`Sum`/`Latest`/etc., growing memory linearly with (unique series in interval) x (intervals since startup). * Drain remaining event-time buckets when the input stream closes. `flush_event_time_buckets` now accepts a `force` flag and a new `flush_final` entry-point is wired into the input-closed arm so in-flight metrics in still-open windows are emitted on shutdown or topology reload, matching system-time semantics. * Reject events for already-emitted windows. Watermark now records the exclusive end (`bucket_key + interval_ms`) of the highest flushed bucket, and `is_too_late` no longer subtracts `allowed_lateness_ms`. `allowed_lateness_ms` keeps its role of delaying bucket close at flush time; once a window is emitted it stays closed. This prevents late events from re-creating closed buckets and emitting duplicate partial aggregates. * Drop events whose (kind, value) is incompatible with the configured mode (for example an `Incremental` event arriving at a `Mean` aggregator) without materialising a bucket. The previous code path always created an empty `event_time_buckets` entry, which then flushed and advanced the watermark, silently rejecting valid in-order events for earlier buckets. Compatibility is now decided up front by `will_be_stored`, dropped events emit `AggregateEventDropped` (rather than the misleading `AggregateEventRecorded`), and `event_time_multi_buckets` is only touched in `Mean`/`Stdev` mode. Adds tests for edge-case behaviour, event-time `Mean` and `Stdev` happy-path flushing, plus an updated changelog entry describing shipped behaviour. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@syedg1 I saw your PR to my branch was closed? I've check your PR and try to address extra edge cases in the last commit. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0942121d68
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ca2c616d24
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
… event-time mode Codex flagged that when event-time Auto mode receives an Absolute sample and then an Incremental sample for the same series/bucket, the Incremental arm's kind-mismatch branch in record_sum_in_map replaced the stored tuple outright, discarding the Absolute sample's EventMetadata. With acknowledgements enabled, that sample's finalizers resolved before the emitted aggregate was actually finalized. Merge metadata unconditionally before conditionally replacing the stored value, mirroring the reverse (Incremental-to-Absolute) path, which already merged correctly. Fold the new regression coverage into the existing event_time_auto_replaces_on_kind_change_before_timestamp_compare test (renamed to event_time_auto_handles_kind_switch_in_both_directions) rather than adding a new test function, keeping the event-time suite at 33 tests. Also trim a few comments in event_time.rs that either narrated the following line or restated the code below them, tightening style parity with transform.rs's terser precedent for equivalent logic. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 12e5179630
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Codex flagged that record_count/record_count_in_map gated the counter increment on `existing.kind == data.kind`, but Count is documented to count both Absolute and Incremental metrics for a series. When a series mixed kinds within one window (system-time) or one bucket (event-time), the second sample's kind mismatch only emitted AggregateUpdateFailed and was silently dropped from the total instead of counted, undercounting the result. `MetricData::update` never inspects kind — only the stored Counter/Counter value types must match, which they always do here — so drop the kind gate and always attempt the update; metadata is now always merged too, matching the other modes' merge-first pattern. Fix applied to both transform.rs (system-time) and event_time.rs, since the two are identical implementations of the same documented mode. Extend count_agg with a mixed-kind case and add event_time_count_counts_mixed_kinds_in_same_bucket to cover event-time. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fa3dd16f91
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Clippy's missing_const_for_fn lint is denied in vector and would fail Check clippy once the fork-PR Test Suite workflow is approved. Co-authored-by: Cursor <cursoragent@cursor.com>
…latest selection When select_latest_by_event_timestamp replaces MetricData with a newer sample, the previous EventMetadata was left as the merge base. Because EventMetadata::merge never overwrites attribution fields such as source_type or datadog_origin_metadata, Latest/Diff/absolute Auto could emit the winning value attributed to the losing sample. On replacement, use the incoming metadata as the base and merge the retained sample's metadata into it so finalizers are still preserved. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9a0027ca80
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…time replacement EventMetadata::merge never overwrites attribution fields such as source_type or datadog_origin_metadata. Any path that replaces retained MetricData must therefore also make the incoming metadata the merge base, or the emitted value is attributed to the superseded sample. Introduce replace_entry and use it for Latest/Diff timestamp selection, Auto kind switches, failed same-kind updates, and Max/Min winners / kind-mismatch replacements. Consolidate the Auto kind-switch coverage into the existing metadata/finalizer test so the suite stays at 33 tests. Co-authored-by: Cursor <cursoragent@cursor.com>
…d helpers Reduce overlapping cases and LoC while keeping the behavioral checks, including both Latest arrival orders. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@pront PR should looks better now. |
…cket Eligible event-time windows are a prefix of the BTreeMap, so flush with take_while instead of visiting every open bucket. Also rename is_too_late to was_bucket_flushed. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@ArunPiduguDD @pront added recommendation, The rest I would like to apply as separate follow up small PRs. |
Master no longer accepts #[configurable(derived)]; field rustdoc already drives the generated config schema. Co-authored-by: Cursor <cursoragent@cursor.com>
Head branch was pushed to by a user without write access

Summary
This PR adds event-time aggregation support to the
aggregatetransform, addressing issues where metrics with different source timestamps but the same processing time are incorrectly aggregated together.I made this PR to address some gaps in #23694. Thank you @adiwab for providing initial implementation.
Problem
Currently, the
aggregatetransform uses system processing time to bucket metrics. This causes issues when:Solution
Introduced an optional
event_timeconfiguration block:Key Changes
Configuration Options:
Event-time aggregation is enabled by presence of the optional
event_timeblock (no separate on/off flag). All sub-fields are optional with sensible defaults:event_time.allowed_lateness_ms: Grace period for accepting late-arriving events, in milliseconds (default:0)event_time.missing_timestamp: How to handle metrics without a timestamp —drop(default) oruse_system_timeevent_time.max_future_ms: Maximum allowed future timestamp drift before an event is rejected as clock-skewed (default:10000ms)Implementation:
interval_msboundaries (Euclidean division, correct for pre-epoch timestamps too)event_time_buckets,event_time_prev_buckets,event_time_multi_buckets) for event-time mode, withevent_time_prev_bucketsbounded to a small rolling window and holding onlyMetricData(noEventMetadata) soDiffmode's delta retention doesn't hold finalizers/acknowledgements past emissionEventMetadata(including finalizers) is merged — not dropped — whenever a sample is superseded by timestamp selection inAuto/Latest/DiffmodesAggregateEventDroppedinternal event, counted throughcomponent_discarded_events_totalVector configuration
How did you test this PR?
The aggregate transform's unit test suite covers 33 tests: the original 17 system-time tests (unchanged, ensuring no regression to default behavior) plus 16 event-time-specific tests, including:
dropanduse_system_timei64/u64boundary values that previously risked overflow or panics)Auto/LatestmodesDiffmode previous-bucket retention (bounded rolling window) vs. non-Diffmodes retaining nothingEventMetadata/finalizer merging on latest-selection, and finalizer release afterDiffbucket retentionevent_timeblock and its documented literalsI've used Sonnet 4.5 to create some scripts that push influxdb metrics to vector with multiple values:
Change Type
Is this a breaking change?
Does this PR include user facing changes?
no-changeloglabel to this PR.References
Notes
@vectordotdev/vectorto reach out to us regarding this PR.pre-pushhook, please see this template.make fmtmake check-clippy(if there are failures it's possible some of them can be fixed withmake clippy-fix)make testgit merge origin masterandgit push.Cargo.lock), pleaserun
make build-licensesto regenerate the license inventory and commit the changes (if any). More details here.