Skip to content

Merge timeseries into develop - #3732

Open
satween wants to merge 61 commits into
developfrom
feature/timeseries
Open

Merge timeseries into develop#3732
satween wants to merge 61 commits into
developfrom
feature/timeseries

Conversation

@satween

@satween satween commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Merges timeseries into develop

Additional Notes

All of the comments here was reviewed with the corresponding separate pull requests.

Review checklist (to be filled by reviewers)

  • Feature or bugfix MUST have appropriate tests (unit, integration, e2e)
  • Make sure you discussed the feature or bugfix with the maintaining team in an Issue
  • Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)

satween and others added 30 commits May 12, 2026 02:01
### What does this PR do?

Adds JSON schemas for the CPU and memory timeseries event types (`timeseries-cpu-schema.json`, `timeseries-memory-schema.json`), registers them in the model-generation Gradle task, and updates the generated `api/apiSurface` and `api/dd-sdk-android-rum.api` files to reflect the new `RumTimeseriesCpuEvent`, `RumTimeseriesMemoryEvent`, and `TimeseriesConfiguration` public surface.

### Motivation

The timeseries feature needs a well-defined wire format (JSON schemas) and generated Kotlin model classes before any collector or serializer code can reference them.

### Additional Notes

The generated Kotlin model classes (`RumTimeseriesCpuEvent`, `RumTimeseriesMemoryEvent`) are produced at build time from these schemas via the existing `generateRumModelsFromJson` task and are not included in this commit.
Aligns timeseries model class names with the existing convention used
by ActionEvent, ErrorEvent, ViewEvent etc. (the inputNameMapping in
generate_rum_models.gradle.kts already strips the Rum prefix that
appears in the JSON schema titles).

- generate_rum_models.gradle.kts: map both schemas to
  Timeseries{Memory,Cpu}Event.
- features/dd-sdk-android-rum/api: regenerate apiSurface and api dump.
…eries-json-schemas-api-surface

`timeseries` RUM-13949: Add timeseries JSON schemas and regenerate API surface
Merge `develop` into `timeseries`

Co-authored-by: satween <1608994+satween@users.noreply.github.com>
Co-authored-by: jonathanmos <48201295+jonathanmos@users.noreply.github.com>
Co-authored-by: hamorillo <hector.morilloprieto@datadoghq.com>
Co-authored-by: 0xnm <4046447+0xnm@users.noreply.github.com>
Co-authored-by: datadog-datadog-prod-us1-2[bot] <261164178+datadog-datadog-prod-us1-2[bot]@users.noreply.github.com>
Co-authored-by: kikoveiga <francisco.veiga@datadoghq.com>
Co-authored-by: sbarrio <sergio.barrio.slocker@gmail.com>
Co-authored-by: timur.valeev <timur.valeev@datadoghq.com>
Merge origin/develop into feature/timeseries
- Add Pipeline, Buffer, DataPoint, Timeseries, TimeseriesFactory types
- Add RumSessionScopeTimeseries and RumSessionScopeTimeseriesFactory
- Wire timeseries start/stop into RumSessionScope (renewSession/stopSession)
- Add NoOpTimeseries and NoOpTimeseriesFactory
- Add unit tests for all new types
…eries-pipeline-infrastructure

`timeseries` [2/6] RUM-13949: Implement timeseries pipeline infrastructure
…rom the existing `CpuVitalReader` vital and wraps them as `DataPoint` values; and `CpuEventSerializer`, which converts a batch of CPU `DataPoint`s into a `RumTimeseriesCpuEvent` JSON object ready for ingestion.
…eries-cpu-support

`timeseries` [3/6] RUM-13949: Add CPU timeseries data-point reader and serializer
Adds `MemoryEventSerializer`, which converts a batch of memory `DataPoint`s (heap + native RSS) into a `RumTimeseriesMemoryEvent` JSON object. Introduces `TimeseriesConfiguration` as the public `@ExperimentalRumApi` configuration class (sampling intervals, batch size, background collection flag). Completes the pipeline with `RumSessionScopeTimeseriesFactory`, which wires CPU and memory readers, serializers, and the `TimeseriesConfiguration` together to create fully configured `RumSessionScopeTimeseries` instances for each new session.

Completes the two metric types and provides the factory needed to tie the pipeline to the RUM session lifecycle.

`MemoryEventSerializer` reports both heap and native RSS in bytes, normalised to a 0–100 percent scale using device `maxMemory`. `RumSessionScopeTimeseriesFactory` creates one pipeline per metric type and dispatches them through the same `Timeseries.Factory` interface. `TimeseriesConfiguration` exposes sampling interval, batch size, and a background-collection flag with sensible defaults.
- Remove executorFactory from TimeseriesConfiguration; executor is provided
  by RumFeature.vitalExecutorService at wiring time, not owned by the config class
- Promote collectInBackground to a class-body property so the apiSurface
  generator picks it up (generator only reads propertyDeclaration nodes)
- Regenerate apiSurface with val collectInBackground: Boolean included
- Apply safe-cast fix in MemoryEventSerializer (as? JsonObject + null-safe chaining)
- Remove executor tests from TimeseriesConfigurationTest

Ref: RUM-13949
Pass the required `scale` argument to `roundToLongSafely` in the delta
encoding path, matching the pattern already used in CpuEventSerializer.
- Make bufferSize/intervalMs/collectInBackground internal to avoid
- UndocumentedPublicProperty detekt violations. Reorder import in
- MemoryEventSerializerTest (ktlint). Regenerate dd-sdk-android-rum.api.
- Replace the primary constructor with an internal constructor and a
- public Builder class (setBufferSize/setIntervalMs/setCollectInBackground/build).
- Update tests and regenerate API surface files.
- Replace `?: error()` in // When blocks with `checkNotNull()` in // Then
- Wrap bare UUID.fromString() call in assertDoesNotThrow { }
- Remove unnecessary newSingleThreadScheduledExecutor entry from detekt_custom_safe_calls.yml

Ref: RUM-13949
…eries-memory-session-factory

`timeseries` [4/6] RUM-13949 Add memory timeseries serializer and session factory
Adds `enableTimeseries()`/`disableTimeseries()` builder methods on `RumConfiguration.Builder`. Wires the `Timeseries.Factory` through `RumFeature` → `DatadogRumMonitor` → `RumApplicationScope` → `RumSessionScope`, so that a new `RumSessionScopeTimeseries` collector is created and started for each sampled session and stopped on session end or SDK teardown. Also enables timeseries in the Kotlin sample app.

Connects the standalone pipeline and public configuration API to the existing RUM session lifecycle, completing the end-to-end data flow from configuration through to event emission.

Existing scope and monitor test scaffolding is updated to pass `timeseriesFactory = null` / a mock factory where required. The `RumFeature.onStop()` ordering test verifies the writer is still live when the final flush fires.
- Restore closing `}` for `createDataWriter` accidentally dropped when
  `createTimeseriesCollectingFactory` was inserted after it
- Add `@OptIn(ExperimentalRumApi::class)` to `createTimeseries` test
  helper to satisfy -Werror on the experimental API usage
- Rename `RumSessionScopeFactoryTest.kt` →
  `RumSessionScopeTimeseriesFactoryTest.kt` to match contained class
  (ktlint filename rule)

Ref: RUM-13949
Adds a self-contained end-to-end test suite for the timeseries pipeline using CSV-driven input fixtures and golden JSON files, without any real Android API dependencies. Includes `CSVReader`, `CsvTimeseries` (a synchronous, executor-free test double mirroring `RumSessionScopeTimeseriesFactory`), `TimeseriesEndToEndTest`, and the accompanying CSV input and expected JSON fixture files.

Provides regression coverage that the full memory and CPU batch outputs match the expected wire format exactly, catching any serialization regressions independently of mock-heavy unit tests.

Fixtures use a fixed 10-sample / 2-batch scenario. Numeric comparisons use a small relative tolerance for floating-point memory_percent values.
Add missing "count" field to all four expected JSON fixtures so they
match the serializer output that now includes a sample count per batch.

Ref: RUM-13949
…eries-rum-session-wiring

`timeseries` [5/6] RUM-13949 Wire timeseries collection into RUM session lifecycle
…eries-e2e-csv-fixtures

`timeseries` [6/6] RUM-13949 Add end-to-end timeseries verification tests with CSV fixtures
…meseries-RUM-16325-dev-merge

# Conflicts:
#	tools/benchmark/src/main/java/com/datadog/benchmark/EndPoint.kt
…16325-dev-merge

RUM-16325 [1/3]: Merge `develop` into `feature/timeseries`
The oneOf-primitive option generator kept its own private knownTypes set
that was never cleared between files, unlike every other generator which
shares (and clears per file) the FileGenerator set. As a result, when two
top-level models contained a structurally identical oneOf of primitives
(e.g. the Path = oneOf[string,integer] from the shared _graphql schema,
referenced by both ResourceEvent and ErrorEvent), the second model's
option subclasses extended the first model's nested sealed class
(ErrorEvent.String : ResourceEvent.Path()), which fails to compile.

Wire the shared knownTypes set into OneOfPrimitiveOptionGenerator so each
model resolves its own nested type. Add a dedicated regression test that
generates two models sharing an identical oneOf-primitive and asserts the
second does not leak a reference to the first's nested type.
Regenerate RUM models and API surface from the updated JSON schemas: new
graphql/stream/trace/transition/vital-duration/view_update schemas and
updated action/error/resource/view definitions.
…16325-schema-update

RUM-16325 `timeseries`: Update RUM JSON schemas and regenerate models
…16325-post-review

RUM-16325 `timeseries`: Post-review fixes for timeseries
satween and others added 19 commits July 31, 2026 17:23
RUM-17613: Merging `develop` into `feature/timeseries`
…develop

Merge `develop` into `feature/timeseries`

Co-authored-by: satween <timur.valeev@datadoghq.com>
Co-authored-by: aleksandr-gringauz <aleksandr.gringauz@datadoghq.com>
Co-authored-by: abrooksv <abrooksv@users.noreply.github.com>
Co-authored-by: leoromanovsky <leo.romanovsky@datadoghq.com>
Co-authored-by: ambushwork <luyi1022@outlook.com>
Rename the internal Timeseries interface to TimeseriesCollector and rename its
implementations to DefaultTimeseriesCollector and
DefaultTimeseriesCollectorFactory, propagating the new names through
RumFeature, the RUM scope tree and the tests. No behaviour change.

Ref: RUM-17613
Co-authored-by: Francisco Veiga <francisco.veiga@datadoghq.com>
…lector-rename

RUM-17613: `timeseries` [1/5] Rename Timeseries abstractions to TimeseriesCollector
Derive the CPU and memory timeseries schemas from _common-schema.json and
replace the hand-written JSON serializers with typed event factories that
populate the full common event shape (os, device, dd, ddtags).
Restrict collection through TimeseriesConfiguration.collectOnly.

Ref: RUM-17613
Array.toSet() over an enum's values() is always safe, so whitelist it
globally instead of suppressing UnsafeThirdPartyFunctionCall at each
call site.
toTimeseriesCpuConnectivity() and toTimeseriesMemoryConnectivity() were
never called: the timeseries event factories don't populate connectivity
at all. Remove them along with their tests and the helper table that only
those tests used.
Pipeline used to read the timeseries name back out of the hand-built JSON
event; it now takes it from EventFactory.eventName, so nothing in
production references these keys anymore. The only remaining caller was a
PipelineTest helper whose JSON shape is never asserted on.
…eseries-schema

RUM-17613: `timeseries` [2/5] Using updated timeseries schema from rum_event_schema
Timeseries batches carried the RumContext captured when RumSessionScope
created the collector, so every event was attributed to whatever view was
active at session start. The collector now tracks the context and hands it to
Pipeline.execute()/flush() per call, and RumSessionScope feeds it the active
context on each handled event.

Pipeline takes over its own synchronization as part of that: reader.read()
stays outside the lock so a concurrent flush() never waits for /proc I/O.

Ref: RUM-17613
…kground-flush

RUM-17613: `timeseries` [3/5] Pass the live RUM context to timeseries pipelines
Sampling kept running while the app sat in background, and the buffered batch
was only written on session stop, so points collected before a backgrounding
could stay unsent for the rest of the session.

The collector now suspends the sampling chain when the active view leaves the
foreground and flushes the buffers at that point, attributing the batch to the
last foreground context. The suspension is delayed by 200 ms to match
ActivityViewTrackingStrategy.STOP_VIEW_DELAY_MS, so an Activity-to-Activity
transition is not mistaken for a backgrounding. Sampling state carries a
generation counter so a suspension pending on an older generation cannot stop a
chain that has since been resumed.

Drops TimeseriesConfiguration.collectInBackground: background suspension is now
unconditional, so the flag no longer has a meaning.

Ref: RUM-17613
The pending suspend read lastForegroundRumContext at fire time, so a
foreground re-entry landing between stopGeneration() and the flush made it
attribute the previous view's batch to the new view. Snapshot the context
when the stop is scheduled instead.
…ckground-suspend

RUM-17613: `timeseries` [4/5] Flush the batch in background
Add a playground activity and an instrumented test that assert CPU and
memory timeseries are collected, flushed on backgrounding and resumed on
return to foreground.
…egration-tests

RUM-17613: `timeseries` [5/5] Add integration tests for timeseries collection
@satween
satween requested review from a team as code owners August 19, 2026 13:41
@datadog-official

datadog-official Bot commented Aug 19, 2026

Copy link
Copy Markdown

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 93.43%
Overall Coverage: 71.95% (+0.16%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 4e1a746 | Docs | View more details | Give us feedback!

@satween satween changed the title Mergin timeseries into develop Merge timeseries into develop Aug 19, 2026
@satween
satween marked this pull request as draft August 19, 2026 13:43

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ff495915ff

ℹ️ 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".

…eries-telemetry

RUM-18101: Supporting `timeseries` apiUsage telemetry.
@codecov-commenter

codecov-commenter commented Aug 19, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.63296% with 34 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.50%. Comparing base (972eab3) to head (cd37cca).
⚠️ Report is 19 commits behind head on develop.

Files with missing lines Patch % Lines
.../internal/timeseries/DefaultTimeseriesCollector.kt 90.14% 3 Missing and 4 partials ⚠️
...lin/com/datadog/android/rum/internal/RumFeature.kt 84.21% 5 Missing and 1 partial ⚠️
.../android/insights/internal/widgets/TimelineView.kt 0.00% 5 Missing ⚠️
...droid/internal/telemetry/InternalTelemetryEvent.kt 0.00% 2 Missing ⚠️
...g/android/rum/internal/domain/scope/RumEventExt.kt 97.67% 2 Missing ⚠️
...rum/internal/timeseries/factory/CpuEventFactory.kt 96.23% 0 Missing and 2 partials ⚠️
.../internal/timeseries/factory/MemoryEventFactory.kt 96.43% 0 Missing and 2 partials ⚠️
.../android/insights/internal/domain/TimelineEvent.kt 87.50% 1 Missing ⚠️
...nsights/internal/overlay/DefaultInsightsOverlay.kt 0.00% 1 Missing ⚠️
...rum/src/main/kotlin/com/datadog/android/rum/Rum.kt 91.67% 0 Missing and 1 partial ⚠️
... and 5 more
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3732      +/-   ##
===========================================
+ Coverage    73.39%   73.50%   +0.11%     
===========================================
  Files          999     1012      +13     
  Lines        36571    37027     +456     
  Branches      6181     6380     +199     
===========================================
+ Hits         26839    27216     +377     
+ Misses        8012     8004       -8     
- Partials      1720     1807      +87     
Files with missing lines Coverage Δ
...roid/insights/internal/DefaultInsightsCollector.kt 69.51% <100.00%> (+0.76%) ⬆️
...kotlin/com/datadog/android/rum/RumConfiguration.kt 92.47% <100.00%> (+0.17%) ⬆️
.../datadog/android/rum/internal/RumSessionTypeExt.kt 100.00% <100.00%> (ø)
...tadog/android/rum/internal/domain/RumDataWriter.kt 90.70% <100.00%> (+0.45%) ⬆️
...ndroid/rum/internal/domain/event/RumEventMapper.kt 100.00% <100.00%> (ø)
...id/rum/internal/domain/event/RumEventSerializer.kt 94.20% <100.00%> (+0.11%) ⬆️
...d/rum/internal/domain/scope/RumApplicationScope.kt 95.45% <100.00%> (+0.11%) ⬆️
.../android/rum/internal/domain/scope/RumViewScope.kt 94.76% <100.00%> (-0.20%) ⬇️
.../datadog/android/rum/internal/timeseries/Buffer.kt 100.00% <100.00%> (ø)
...tadog/android/rum/internal/timeseries/DataPoint.kt 100.00% <100.00%> (ø)
... and 22 more

... and 108 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

satween and others added 2 commits August 21, 2026 12:15
…v-2-timeseries

# Conflicts:
#	features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/RumDataWriterTest.kt
@satween
satween marked this pull request as ready for review August 21, 2026 14:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants