From 7d5e421b600362d61a9512ee3c9cfa872785a8cf Mon Sep 17 00:00:00 2001 From: Barbora Plasovska Date: Tue, 7 Jul 2026 15:11:25 +0200 Subject: [PATCH 1/4] RUM-17173 Add timeseries configuration support for memory and CPU RUM metrics --- .../datadog/reactnative/DdSdkConfiguration.kt | 33 +++++- .../reactnative/DdSdkConfigurationExt.kt | 35 +++++- .../reactnative/DdSdkNativeInitialization.kt | 24 +++++ .../DdSdkNativeInitializationTest.kt | 3 + .../com/datadog/reactnative/DdSdkTest.kt | 100 ++++++++++++++++++ .../input/complete-configuration.json | 4 + .../core/datadog-configuration.schema.json | 29 +++++ .../core/ios/Sources/DdSdkConfiguration.swift | 11 +- .../Sources/DdSdkNativeInitialization.swift | 6 +- .../ios/Sources/RNDdSdkConfiguration.swift | 25 ++++- .../DdSdkNativeInitializationTests.swift | 4 + packages/core/ios/Tests/DdSdkTests.swift | 33 +++++- .../Fixtures/complete-configuration.json | 4 + .../DdSdkReactNativeConfiguration.test.ts | 3 + .../core/src/config/FileBasedConfiguration.ts | 3 +- .../src/config/FileBasedConfiguration.type.ts | 2 + .../__tests__/FileBasedConfiguration.test.ts | 6 ++ .../configuration-all-fields.json | 6 +- .../src/config/features/RumConfiguration.ts | 5 + .../config/features/RumConfiguration.type.ts | 8 +- .../config/features/RumConfigurationNative.ts | 3 + .../config/types/TimeseriesConfiguration.ts | 40 +++++++ packages/core/src/config/types/index.ts | 1 + 23 files changed, 376 insertions(+), 12 deletions(-) create mode 100644 packages/core/src/config/types/TimeseriesConfiguration.ts diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfiguration.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfiguration.kt index 50a3ae377..a03ce2d96 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfiguration.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfiguration.kt @@ -65,6 +65,7 @@ data class DdSdkConfiguration( * @param initialResourceThreshold The amount of time after a view starts where a Resource should be considered when calculating Time to Network-Settled (TNS). * @param telemetrySampleRate The sample rate (between 0 and 100) of telemetry events. * @param customEndpoint Custom RUM intake endpoint used to override the default Datadog intake. + * @param timeseries Experimental: configuration for memory and CPU timeseries collection. */ data class RumConfiguration( val applicationId: String, @@ -82,7 +83,26 @@ data class RumConfiguration( val trackNonFatalAnrs: Boolean? = null, val initialResourceThreshold: Double? = null, val telemetrySampleRate: Double? = null, - val customEndpoint: String? = null + val customEndpoint: String? = null, + val timeseries: TimeseriesConfiguration? = null +) + +/** + * Experimental: configuration for memory and CPU timeseries collection. + * Requires a native SDK build with timeseries support. + * + * @param enabled Enables collection of memory and CPU timeseries events. + * @param bufferSize The number of samples collected before a timeseries batch is flushed. + * @param intervalMs The sampling interval in milliseconds. + * @param collectInBackground Whether to keep sampling timeseries when the app is in background. + * @param useDeltaCompression Whether to encode each sample as a delta from the previous value instead of an absolute value. + */ +data class TimeseriesConfiguration( + val enabled: Boolean, + val bufferSize: Double? = null, + val intervalMs: Double? = null, + val collectInBackground: Boolean? = null, + val useDeltaCompression: Boolean? = null ) /** @@ -157,7 +177,16 @@ internal data class JSONRumConfiguration( val vitalsUpdateFrequency: String? = null, val trackMemoryWarnings: Boolean? = null, val telemetrySampleRate: Double? = null, - val customEndpoint: String? = null + val customEndpoint: String? = null, + val timeseries: JSONTimeseriesConfiguration? = null +) + +internal data class JSONTimeseriesConfiguration( + val enabled: Boolean? = null, + val bufferSize: Double? = null, + val intervalMs: Double? = null, + val collectInBackground: Boolean? = null, + val useDeltaCompression: Boolean? = null ) internal data class JSONLogsConfiguration( diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfigurationExt.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfigurationExt.kt index 0bf90624c..ebd041d68 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfigurationExt.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfigurationExt.kt @@ -45,7 +45,8 @@ internal fun ReadableMap.asDdSdkConfiguration(): DdSdkConfiguration { trackNonFatalAnrs = rm.getBooleanOrNull("trackNonFatalAnrs"), initialResourceThreshold = rm.getDoubleOrNull("initialResourceThreshold"), telemetrySampleRate = rm.getDoubleOrNull("telemetrySampleRate"), - customEndpoint = rm.getString("customEndpoint") + customEndpoint = rm.getString("customEndpoint"), + timeseries = rm.getMap("timeseries")?.asTimeseriesConfiguration() ) } @@ -86,6 +87,16 @@ internal fun ReadableMap.asDdSdkConfiguration(): DdSdkConfiguration { } +internal fun ReadableMap.asTimeseriesConfiguration(): TimeseriesConfiguration { + return TimeseriesConfiguration( + enabled = getBooleanOrNull("enabled") ?: false, + bufferSize = getDoubleOrNull("bufferSize"), + intervalMs = getDoubleOrNull("intervalMs"), + collectInBackground = getBooleanOrNull("collectInBackground"), + useDeltaCompression = getBooleanOrNull("useDeltaCompression") + ) +} + internal fun ReadableMap.asConfigurationForTelemetry(): ConfigurationForTelemetry { return ConfigurationForTelemetry( initializationType = getString("initializationType"), @@ -187,7 +198,8 @@ internal fun JSONDdSdkConfiguration.asDdSdkConfiguration(): DdSdkConfiguration { initialResourceThreshold = rum.initialResourceThreshold ?: DefaultConfiguration.initialResourceThreshold, telemetrySampleRate = rum.telemetrySampleRate?.toDouble() ?: DefaultConfiguration.telemetrySampleRate, - customEndpoint = rum.customEndpoint + customEndpoint = rum.customEndpoint, + timeseries = rum.timeseries?.asTimeseriesConfiguration() ) } @@ -229,6 +241,16 @@ internal fun JSONDdSdkConfiguration.asDdSdkConfiguration(): DdSdkConfiguration { } +internal fun JSONTimeseriesConfiguration.asTimeseriesConfiguration(): TimeseriesConfiguration { + return TimeseriesConfiguration( + enabled = this.enabled ?: false, + bufferSize = this.bufferSize, + intervalMs = this.intervalMs, + collectInBackground = this.collectInBackground, + useDeltaCompression = this.useDeltaCompression + ) +} + internal fun JSONProxyConfiguration.asProxyConfig(): Pair? { return buildProxyConfig(type, address, port, username, password) } @@ -331,6 +353,15 @@ internal fun DdSdkConfiguration.toReadableMap(): ReadableMap { rum.initialResourceThreshold?.let { rumMap.putDouble("initialResourceThreshold", it) } rum.telemetrySampleRate?.let { rumMap.putDouble("telemetrySampleRate", it) } rum.customEndpoint?.let { rumMap.putString("customEndpoint", it) } + rum.timeseries?.let { timeseries -> + val timeseriesMap = WritableNativeMap() + timeseriesMap.putBoolean("enabled", timeseries.enabled) + timeseries.bufferSize?.let { timeseriesMap.putDouble("bufferSize", it) } + timeseries.intervalMs?.let { timeseriesMap.putDouble("intervalMs", it) } + timeseries.collectInBackground?.let { timeseriesMap.putBoolean("collectInBackground", it) } + timeseries.useDeltaCompression?.let { timeseriesMap.putBoolean("useDeltaCompression", it) } + rumMap.putMap("timeseries", timeseriesMap) + } map.putMap("rumConfiguration", rumMap) } diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkNativeInitialization.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkNativeInitialization.kt index ae9ee7118..1ba3ec82f 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkNativeInitialization.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkNativeInitialization.kt @@ -19,6 +19,7 @@ import com.datadog.android.event.EventMapper import com.datadog.android.log.Logs import com.datadog.android.log.LogsConfiguration import com.datadog.android.privacy.TrackingConsent +import com.datadog.android.rum.ExperimentalRumApi import com.datadog.android.rum.Rum import com.datadog.android.rum.RumConfiguration import com.datadog.android._InternalProxy @@ -27,6 +28,7 @@ import com.datadog.android.rum.configuration.VitalsUpdateFrequency import com.datadog.android.rum.metric.networksettled.TimeBasedInitialResourceIdentifier import com.datadog.android.rum.model.ActionEvent import com.datadog.android.rum.model.ResourceEvent +import com.datadog.android.rum.timeseries.TimeseriesConfiguration as NativeTimeseriesConfiguration import com.datadog.android.rum.tracking.ActivityViewTrackingStrategy import com.datadog.android.telemetry.model.TelemetryConfigurationEvent import com.datadog.android.trace.Trace @@ -254,11 +256,33 @@ class DdSdkNativeInitialization internal constructor( configBuilder.setInitialResourceIdentifier(TimeBasedInitialResourceIdentifier(milliseconds)) } + configuration.rumConfiguration?.timeseries?.let { timeseries -> + setTimeseriesConfiguration(configBuilder, timeseries) + } + configBuilder.setSessionListener(DdSdkSessionStartedListener.getInstance()) return configBuilder.build() } + @OptIn(ExperimentalRumApi::class) + private fun setTimeseriesConfiguration( + configBuilder: RumConfiguration.Builder, + timeseries: TimeseriesConfiguration + ) { + if (!timeseries.enabled) { + return + } + + val nativeConfigBuilder = NativeTimeseriesConfiguration.Builder() + timeseries.bufferSize?.let { nativeConfigBuilder.setBufferSize(it.toInt()) } + timeseries.intervalMs?.let { nativeConfigBuilder.setIntervalMs(it.toLong()) } + timeseries.collectInBackground?.let { nativeConfigBuilder.collectInBackground(it) } + timeseries.useDeltaCompression?.let { nativeConfigBuilder.useDeltaCompression(it) } + + configBuilder.setTimeseriesConfiguration(nativeConfigBuilder.build()) + } + private fun buildLogsConfiguration(configuration: DdSdkConfiguration): LogsConfiguration { val configBuilder = LogsConfiguration.Builder() configuration.logsConfiguration?.customEndpoint?.let { diff --git a/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdSdkNativeInitializationTest.kt b/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdSdkNativeInitializationTest.kt index 4e9cb24c7..ad8799c9c 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdSdkNativeInitializationTest.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdSdkNativeInitializationTest.kt @@ -144,6 +144,8 @@ internal class DdSdkNativeInitializationTest { "[B3MULTI, TRACECONTEXT]" ) assertThat(configuration.rumConfiguration?.initialResourceThreshold).isEqualTo(0.5) + assertThat(configuration.rumConfiguration?.timeseries?.enabled).isEqualTo(true) + assertThat(configuration.rumConfiguration?.timeseries?.bufferSize).isEqualTo(15.0) } @Test @@ -192,6 +194,7 @@ internal class DdSdkNativeInitializationTest { assertThat(configuration.rumConfiguration?.firstPartyHosts).isNull() assertThat(configuration.logsConfiguration?.customEndpoint).isNull() assertThat(configuration.traceConfiguration?.customEndpoint).isNull() + assertThat(configuration.rumConfiguration?.timeseries).isNull() } @Test diff --git a/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdSdkTest.kt b/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdSdkTest.kt index b29bb4857..5c4538e0b 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdSdkTest.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdSdkTest.kt @@ -2368,6 +2368,106 @@ internal class DdSdkTest { } } + @Test + fun `𝕄 initialize native SDK 𝕎 initialize() {timeseries enabled}`( + @Forgery configuration: DdSdkConfiguration + ) { + // Given + val rumConfiguration = configuration.rumConfiguration?.copy( + timeseries = TimeseriesConfiguration(enabled = true, bufferSize = 15.0) + ) + val bridgeConfiguration = configuration.copy( + rumConfiguration = rumConfiguration + ) + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() + + val rumMock = org.mockito.Mockito.mockStatic(Rum::class.java) + val traceMock = org.mockito.Mockito.mockStatic(Trace::class.java) + val logsMock = org.mockito.Mockito.mockStatic(Logs::class.java) + + try { + rumMock.`when` { Rum.enable(any(), any()) }.then { } + logsMock.`when` { Logs.enable(any(), any()) }.then { } + traceMock.`when` { Trace.enable(any(), any()) }.then { } + + // When + testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) + + // Then + inOrder(mockDatadog) { + verify(mockDatadog).initialize( + same(mockContext), + sdkConfigCaptor.capture(), + any() + ) + rumMock.verify { Rum.enable(rumConfigCaptor.capture(), any()) } + traceMock.verify { Trace.enable(traceConfigCaptor.capture(), any()) } + logsMock.verify { Logs.enable(logsConfigCaptor.capture(), any()) } + } + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { + it.hasField("timeseriesConfiguration") { ts -> + ts.hasFieldEqualTo("bufferSize", 15) + } + } + } finally { + rumMock.close() + logsMock.close() + traceMock.close() + } + } + + @Test + fun `𝕄 initialize native SDK 𝕎 initialize() {timeseries disabled by default}`( + @Forgery configuration: DdSdkConfiguration + ) { + // Given + val rumConfiguration = configuration.rumConfiguration?.copy(timeseries = null) + val bridgeConfiguration = configuration.copy( + rumConfiguration = rumConfiguration + ) + val sdkConfigCaptor = argumentCaptor() + val rumConfigCaptor = argumentCaptor() + val logsConfigCaptor = argumentCaptor() + val traceConfigCaptor = argumentCaptor() + + val rumMock = org.mockito.Mockito.mockStatic(Rum::class.java) + val traceMock = org.mockito.Mockito.mockStatic(Trace::class.java) + val logsMock = org.mockito.Mockito.mockStatic(Logs::class.java) + + try { + rumMock.`when` { Rum.enable(any(), any()) }.then { } + logsMock.`when` { Logs.enable(any(), any()) }.then { } + traceMock.`when` { Trace.enable(any(), any()) }.then { } + + // When + testedBridgeSdk.initialize(bridgeConfiguration.toReadableJavaOnlyMap(), mockPromise) + + // Then + inOrder(mockDatadog) { + verify(mockDatadog).initialize( + same(mockContext), + sdkConfigCaptor.capture(), + any() + ) + rumMock.verify { Rum.enable(rumConfigCaptor.capture(), any()) } + traceMock.verify { Trace.enable(traceConfigCaptor.capture(), any()) } + logsMock.verify { Logs.enable(logsConfigCaptor.capture(), any()) } + } + assertThat(rumConfigCaptor.firstValue) + .hasField("featureConfiguration") { + it.hasFieldEqualTo("timeseriesConfiguration", null) + } + } finally { + rumMock.close() + logsMock.close() + traceMock.close() + } + } + @Test fun `𝕄 initialize native SDK 𝕎 initialize() {never vitals frequency update}`( @Forgery configuration: DdSdkConfiguration diff --git a/packages/core/android/src/test/resources/input/complete-configuration.json b/packages/core/android/src/test/resources/input/complete-configuration.json index 29bf0dd27..0c2a1ad56 100644 --- a/packages/core/android/src/test/resources/input/complete-configuration.json +++ b/packages/core/android/src/test/resources/input/complete-configuration.json @@ -30,6 +30,10 @@ "resourceTraceSampleRate": 33, "trackBackgroundEvents": true, "trackFrustrations": false, + "timeseries": { + "enabled": true, + "bufferSize": 15 + }, "firstPartyHosts": [ { "match": "example.com", diff --git a/packages/core/datadog-configuration.schema.json b/packages/core/datadog-configuration.schema.json index be0a2d84e..63c92d6c3 100644 --- a/packages/core/datadog-configuration.schema.json +++ b/packages/core/datadog-configuration.schema.json @@ -262,6 +262,35 @@ "customEndpoint": { "description": "Target a custom server for RUM.", "type": "string" + }, + "timeseries": { + "description": "Experimental: configuration for memory and CPU timeseries collection. Requires a native SDK build with timeseries support.", + "type": "object", + "properties": { + "enabled": { + "description": "Enables collection of memory and CPU timeseries events.", + "type": "boolean" + }, + "bufferSize": { + "description": "The number of samples collected before a timeseries batch is flushed. iOS and Android only.", + "type": "integer" + }, + "intervalMs": { + "description": "The sampling interval in milliseconds. Android only.", + "type": "integer" + }, + "collectInBackground": { + "description": "Whether to keep sampling timeseries when the app is in background. Android only.", + "type": "boolean" + }, + "useDeltaCompression": { + "description": "Whether to encode each sample as a delta from the previous value instead of an absolute value. Android only.", + "type": "boolean" + } + }, + "required": [ + "enabled" + ] } }, "required": [ diff --git a/packages/core/ios/Sources/DdSdkConfiguration.swift b/packages/core/ios/Sources/DdSdkConfiguration.swift index fd8e8f3e1..7b6b4bf49 100644 --- a/packages/core/ios/Sources/DdSdkConfiguration.swift +++ b/packages/core/ios/Sources/DdSdkConfiguration.swift @@ -103,6 +103,9 @@ public class DdSdkConfiguration: NSObject { /// - trackMemoryWarnings: Whether memory warning events should be tracked. /// - telemetrySampleRate: Sampling rate (0–100) for internal telemetry emitted via RUM. /// - customEndpoint: A custom RUM intake endpoint to override the default Datadog intake. +/// - enableTimeseries: Experimental: enables collection of memory and CPU timeseries events. +/// Requires a native SDK build with timeseries support. +/// - timeseriesBatchSize: The number of samples collected before a timeseries batch is flushed. public class RumConfiguration: NSObject { public var applicationId: String = "" public var trackFrustrations: Bool? = true @@ -122,6 +125,8 @@ public class RumConfiguration: NSObject { public var trackMemoryWarnings: Bool? = nil public var telemetrySampleRate: Double? = nil public var customEndpoint: String? = nil + public var enableTimeseries: Bool? = nil + public var timeseriesBatchSize: Double? = nil init( applicationId: String, @@ -141,7 +146,9 @@ public class RumConfiguration: NSObject { initialResourceThreshold: Double?, trackMemoryWarnings: Bool?, telemetrySampleRate: Double?, - customEndpoint: String? + customEndpoint: String?, + enableTimeseries: Bool? = nil, + timeseriesBatchSize: Double? = nil ) { self.applicationId = applicationId self.trackFrustrations = trackFrustrations @@ -161,6 +168,8 @@ public class RumConfiguration: NSObject { self.trackMemoryWarnings = trackMemoryWarnings self.telemetrySampleRate = telemetrySampleRate self.customEndpoint = customEndpoint + self.enableTimeseries = enableTimeseries + self.timeseriesBatchSize = timeseriesBatchSize } } diff --git a/packages/core/ios/Sources/DdSdkNativeInitialization.swift b/packages/core/ios/Sources/DdSdkNativeInitialization.swift index c46ddd145..34d666c65 100644 --- a/packages/core/ios/Sources/DdSdkNativeInitialization.swift +++ b/packages/core/ios/Sources/DdSdkNativeInitialization.swift @@ -236,7 +236,11 @@ public class DdSdkNativeInitialization: NSObject { trackMemoryWarnings: rumConfig.trackMemoryWarnings ?? DefaultConfiguration.trackMemoryWarnings, telemetrySampleRate: Float( - rumConfig.telemetrySampleRate ?? DefaultConfiguration.telemetrySampleRate) + rumConfig.telemetrySampleRate ?? DefaultConfiguration.telemetrySampleRate), + enableTimeseries: rumConfig.enableTimeseries + ?? DefaultConfiguration.enableTimeseries, + timeseriesBatchSize: Int( + rumConfig.timeseriesBatchSize ?? DefaultConfiguration.timeseriesBatchSize) ) } diff --git a/packages/core/ios/Sources/RNDdSdkConfiguration.swift b/packages/core/ios/Sources/RNDdSdkConfiguration.swift index bd84625b3..a4e06dbda 100644 --- a/packages/core/ios/Sources/RNDdSdkConfiguration.swift +++ b/packages/core/ios/Sources/RNDdSdkConfiguration.swift @@ -71,6 +71,10 @@ extension NSDictionary { let telemetrySampleRate = rumDict["telemetrySampleRate"] as? Double let customEndpoint = rumDict["customEndpoint"] as? String + let timeseriesDict = rumDict["timeseries"] as? NSDictionary + let enableTimeseries = timeseriesDict?["enabled"] as? Bool + let timeseriesBatchSize = timeseriesDict?["bufferSize"] as? Double + rumConfiguration = RumConfiguration( applicationId: applicationId, trackFrustrations: trackFrustrations ?? DefaultConfiguration.trackFrustrations, @@ -98,7 +102,10 @@ extension NSDictionary { ?? DefaultConfiguration.trackMemoryWarnings, telemetrySampleRate: telemetrySampleRate ?? DefaultConfiguration.telemetrySampleRate, - customEndpoint: customEndpoint + customEndpoint: customEndpoint, + enableTimeseries: enableTimeseries ?? DefaultConfiguration.enableTimeseries, + timeseriesBatchSize: timeseriesBatchSize + ?? DefaultConfiguration.timeseriesBatchSize ) } else { rumConfiguration = nil @@ -284,6 +291,8 @@ internal struct DefaultConfiguration { static let bundleLogsWithTraces = true static let trackWatchdogTerminations = false static let trackMemoryWarnings = true + static let enableTimeseries = false + static let timeseriesBatchSize = 30.0 } extension Dictionary where Key == String, Value == AnyObject { @@ -357,6 +366,15 @@ extension Dictionary where Key == String, Value == AnyObject { let firstPartyHosts = firstPartyHostsArray?.asFirstPartyHosts() ?? DefaultConfiguration.firstPartyHosts + let timeseriesDict = rum["timeseries"] as? [String: Any?] + let enableTimeseries = timeseriesDict?["enabled"] as? Bool + let timeseriesBatchSizeRaw = timeseriesDict?["bufferSize"] + let timeseriesBatchSize: Double? = { + if let v = timeseriesBatchSizeRaw as? Double { return v } + if let v = timeseriesBatchSizeRaw as? Int { return Double(v) } + return nil + }() + rumConfiguration = RumConfiguration( applicationId: applicationId, trackFrustrations: rum["trackFrustrations"] as? Bool @@ -387,7 +405,10 @@ extension Dictionary where Key == String, Value == AnyObject { ?? DefaultConfiguration.trackMemoryWarnings, telemetrySampleRate: (rum["telemetrySampleRate"] as? Double) ?? DefaultConfiguration.telemetrySampleRate, - customEndpoint: rum["customEndpoint"] as? String + customEndpoint: rum["customEndpoint"] as? String, + enableTimeseries: enableTimeseries ?? DefaultConfiguration.enableTimeseries, + timeseriesBatchSize: timeseriesBatchSize + ?? DefaultConfiguration.timeseriesBatchSize ) } else { rumConfiguration = nil diff --git a/packages/core/ios/Tests/DdSdkNativeInitializationTests.swift b/packages/core/ios/Tests/DdSdkNativeInitializationTests.swift index cb6a6c500..577d9309b 100644 --- a/packages/core/ios/Tests/DdSdkNativeInitializationTests.swift +++ b/packages/core/ios/Tests/DdSdkNativeInitializationTests.swift @@ -66,6 +66,8 @@ class DdSdkNativeInitializationTests: XCTestCase { let expectedFirstPartyHosts: [String: Set]? = ["example.com": [.b3multi, .tracecontext]] XCTAssertEqual(configuration?.rumConfiguration?.firstPartyHosts, expectedFirstPartyHosts) XCTAssertEqual(configuration?.rumConfiguration?.initialResourceThreshold, 0.5) + XCTAssertEqual(configuration?.rumConfiguration?.enableTimeseries, true) + XCTAssertEqual(configuration?.rumConfiguration?.timeseriesBatchSize, 15.0) } func testReturnsConfigurationWithMinimalData() { @@ -104,6 +106,8 @@ class DdSdkNativeInitializationTests: XCTestCase { let expectedFirstPartyHosts: [String: Set]? = [:] XCTAssertEqual(configuration?.rumConfiguration?.firstPartyHosts, expectedFirstPartyHosts) XCTAssertEqual(configuration?.rumConfiguration?.initialResourceThreshold, nil) + XCTAssertEqual(configuration?.rumConfiguration?.enableTimeseries, false) + XCTAssertEqual(configuration?.rumConfiguration?.timeseriesBatchSize, 30.0) } func testPrintsMessageWithIncorrectFile() { diff --git a/packages/core/ios/Tests/DdSdkTests.swift b/packages/core/ios/Tests/DdSdkTests.swift index bc13c4f98..fedb5b811 100644 --- a/packages/core/ios/Tests/DdSdkTests.swift +++ b/packages/core/ios/Tests/DdSdkTests.swift @@ -1049,6 +1049,34 @@ class DdSdkTests: XCTestCase { XCTAssertEqual(ddConfig.vitalsUpdateFrequency, nil) } + func testBuildConfigurationEnabledTimeseries() { + let rumConfiguration: RumConfiguration = makeDefaultRumConfiguration() + rumConfiguration.enableTimeseries = true + rumConfiguration.timeseriesBatchSize = 15.0 + let configuration: DdSdkConfiguration = .mockAny(rumConfiguration: rumConfiguration) + + let ddConfig = DdSdkNativeInitialization().buildRumConfiguration( + configuration: configuration + ) + + XCTAssertEqual(ddConfig.enableTimeseries, true) + XCTAssertEqual(ddConfig.timeseriesBatchSize, 15) + } + + func testBuildConfigurationDisabledTimeseriesByDefault() { + let rumConfiguration: RumConfiguration = makeDefaultRumConfiguration() + rumConfiguration.enableTimeseries = nil + rumConfiguration.timeseriesBatchSize = nil + let configuration: DdSdkConfiguration = .mockAny(rumConfiguration: rumConfiguration) + + let ddConfig = DdSdkNativeInitialization().buildRumConfiguration( + configuration: configuration + ) + + XCTAssertEqual(ddConfig.enableTimeseries, false) + XCTAssertEqual(ddConfig.timeseriesBatchSize, 30) + } + func testBuildConfigurationAverageUploadFrequency() { let configuration: DdSdkConfiguration = .mockAny(uploadFrequency: "AVERAGE") @@ -1781,7 +1809,9 @@ func makeDefaultRumConfiguration() -> RumConfiguration { initialResourceThreshold: nil, trackMemoryWarnings: true, telemetrySampleRate: 45.0, - customEndpoint: nil + customEndpoint: nil, + enableTimeseries: nil, + timeseriesBatchSize: nil ) } @@ -1908,6 +1938,7 @@ extension NSDictionary { rumConfig["nativeInteractionTracking"] = rumConfiguration?["nativeInteractionTracking"] rumConfig["customEndpoint"] = rumConfiguration?["customEndpoint"] rumConfig["trackFrustrations"] = rumConfiguration?["trackFrustrations"] + rumConfig["timeseries"] = rumConfiguration?["timeseries"] logsConfig["bundleLogsWithRum"] = logsConfiguration?["bundleLogsWithRum"] logsConfig["bundleLogsWithTraces"] = logsConfiguration?["bundleLogsWithTraces"] diff --git a/packages/core/ios/Tests/Fixtures/complete-configuration.json b/packages/core/ios/Tests/Fixtures/complete-configuration.json index d2648a289..4123ee324 100644 --- a/packages/core/ios/Tests/Fixtures/complete-configuration.json +++ b/packages/core/ios/Tests/Fixtures/complete-configuration.json @@ -30,6 +30,10 @@ "resourceTraceSampleRate": 33, "trackBackgroundEvents": true, "trackFrustrations": false, + "timeseries": { + "enabled": true, + "bufferSize": 15 + }, "firstPartyHosts": [ { "match": "example.com", diff --git a/packages/core/src/__tests__/DdSdkReactNativeConfiguration.test.ts b/packages/core/src/__tests__/DdSdkReactNativeConfiguration.test.ts index 207d9abdd..9e398986c 100644 --- a/packages/core/src/__tests__/DdSdkReactNativeConfiguration.test.ts +++ b/packages/core/src/__tests__/DdSdkReactNativeConfiguration.test.ts @@ -71,6 +71,7 @@ describe('DdSdkReactNativeConfiguration', () => { "resourceTraceSampleRate": 100, "sessionSampleRate": 100, "telemetrySampleRate": 20, + "timeseries": undefined, "trackBackgroundEvents": false, "trackErrors": false, "trackFrustrations": true, @@ -215,6 +216,7 @@ describe('DdSdkReactNativeConfiguration', () => { "resourceTraceSampleRate": 80, "sessionSampleRate": 80, "telemetrySampleRate": 20, + "timeseries": undefined, "trackBackgroundEvents": true, "trackErrors": true, "trackFrustrations": true, @@ -318,6 +320,7 @@ describe('DdSdkReactNativeConfiguration', () => { "resourceTraceSampleRate": 0, "sessionSampleRate": 0, "telemetrySampleRate": 0, + "timeseries": undefined, "trackBackgroundEvents": false, "trackErrors": false, "trackFrustrations": false, diff --git a/packages/core/src/config/FileBasedConfiguration.ts b/packages/core/src/config/FileBasedConfiguration.ts index c226050c0..939e1bed1 100644 --- a/packages/core/src/config/FileBasedConfiguration.ts +++ b/packages/core/src/config/FileBasedConfiguration.ts @@ -206,7 +206,8 @@ export const getJSONConfiguration = ( telemetrySampleRate: configuration.rumConfiguration.telemetrySampleRate, nativeInteractionTracking: - configuration.rumConfiguration.nativeInteractionTracking + configuration.rumConfiguration.nativeInteractionTracking, + timeseries: configuration.rumConfiguration.timeseries } }), ...(configuration.traceConfiguration !== undefined && { diff --git a/packages/core/src/config/FileBasedConfiguration.type.ts b/packages/core/src/config/FileBasedConfiguration.type.ts index 693fa5738..e2a546938 100644 --- a/packages/core/src/config/FileBasedConfiguration.type.ts +++ b/packages/core/src/config/FileBasedConfiguration.type.ts @@ -11,6 +11,7 @@ import type { BatchSize, ProxyConfiguration, SdkVerbosity, + TimeseriesConfiguration, TrackingConsent, UploadFrequency, VitalsUpdateFrequency @@ -54,6 +55,7 @@ export interface JsonConfiguration extends CoreConfigurationOptions { trackWatchdogTerminations?: boolean; vitalsUpdateFrequency?: VitalsUpdateFrequency; telemetrySampleRate?: number; + timeseries?: TimeseriesConfiguration; }; traceConfiguration?: { customEndpoint?: string; diff --git a/packages/core/src/config/__tests__/FileBasedConfiguration.test.ts b/packages/core/src/config/__tests__/FileBasedConfiguration.test.ts index 5b062447f..bc17f47dd 100644 --- a/packages/core/src/config/__tests__/FileBasedConfiguration.test.ts +++ b/packages/core/src/config/__tests__/FileBasedConfiguration.test.ts @@ -65,6 +65,10 @@ describe('FileBasedConfiguration', () => { "resourceTraceSampleRate": 33, "sessionSampleRate": 100, "telemetrySampleRate": 20, + "timeseries": { + "bufferSize": 15, + "enabled": true, + }, "trackBackgroundEvents": true, "trackErrors": true, "trackFrustrations": true, @@ -177,6 +181,7 @@ describe('FileBasedConfiguration', () => { "resourceTraceSampleRate": 33, "sessionSampleRate": 100, "telemetrySampleRate": 20, + "timeseries": undefined, "trackBackgroundEvents": false, "trackErrors": true, "trackFrustrations": true, @@ -241,6 +246,7 @@ describe('FileBasedConfiguration', () => { "resourceTraceSampleRate": 100, "sessionSampleRate": 100, "telemetrySampleRate": 20, + "timeseries": undefined, "trackBackgroundEvents": false, "trackErrors": false, "trackFrustrations": true, diff --git a/packages/core/src/config/__tests__/__fixtures__/configuration-all-fields.json b/packages/core/src/config/__tests__/__fixtures__/configuration-all-fields.json index 3b5d15d59..8e7480f15 100644 --- a/packages/core/src/config/__tests__/__fixtures__/configuration-all-fields.json +++ b/packages/core/src/config/__tests__/__fixtures__/configuration-all-fields.json @@ -32,7 +32,11 @@ "trackBackgroundEvents": true, "trackMemoryWarnings": false, "trackWatchdogTerminations": true, - "vitalsUpdateFrequency": "NEVER" + "vitalsUpdateFrequency": "NEVER", + "timeseries": { + "enabled": true, + "bufferSize": 15 + } }, "traceConfiguration": { "customEndpoint": "https://example.com/trace" diff --git a/packages/core/src/config/features/RumConfiguration.ts b/packages/core/src/config/features/RumConfiguration.ts index 3ab70409c..e701587a7 100644 --- a/packages/core/src/config/features/RumConfiguration.ts +++ b/packages/core/src/config/features/RumConfiguration.ts @@ -7,6 +7,7 @@ import type { ActionEventMapper } from '../../rum/eventMappers/actionEventMapper import type { ErrorEventMapper } from '../../rum/eventMappers/errorEventMapper'; import type { ResourceEventMapper } from '../../rum/eventMappers/resourceEventMapper'; import type { FirstPartyHost } from '../../rum/types'; +import type { TimeseriesConfiguration } from '../types'; import { VitalsUpdateFrequency } from '../types'; import type { @@ -31,6 +32,7 @@ const DEFAULTS = { resourceTraceSampleRate: 100.0, sessionSampleRate: 100.0, telemetrySampleRate: 20.0, + timeseries: undefined, trackBackgroundEvents: false, trackErrors: false, trackFrustrations: true, @@ -100,6 +102,9 @@ export class RumConfiguration implements RumConfigurationType { // Telemetry Sample Rate public telemetrySampleRate: number = DEFAULTS.telemetrySampleRate; + // Experimental Timeseries Configuration + public timeseries?: TimeseriesConfiguration = DEFAULTS.timeseries; + // Track Background Events Enabled public trackBackgroundEvents: boolean = DEFAULTS.trackBackgroundEvents; diff --git a/packages/core/src/config/features/RumConfiguration.type.ts b/packages/core/src/config/features/RumConfiguration.type.ts index 0a2094ece..60c2286aa 100644 --- a/packages/core/src/config/features/RumConfiguration.type.ts +++ b/packages/core/src/config/features/RumConfiguration.type.ts @@ -7,7 +7,7 @@ import type { ActionEventMapper } from '../../rum/eventMappers/actionEventMapper import type { ErrorEventMapper } from '../../rum/eventMappers/errorEventMapper'; import type { ResourceEventMapper } from '../../rum/eventMappers/resourceEventMapper'; import type { FirstPartyHost } from '../../rum/types'; -import type { VitalsUpdateFrequency } from '../types'; +import type { TimeseriesConfiguration, VitalsUpdateFrequency } from '../types'; /** * Required RUM configuration values. @@ -116,6 +116,12 @@ export interface RumConfigurationOptions { */ sessionSampleRate?: number; + /** + * Experimental: configuration for memory and CPU timeseries collection. + * Requires a native SDK build with timeseries support. + */ + timeseries?: TimeseriesConfiguration; + /** * Enables tracking of background RUM events. */ diff --git a/packages/core/src/config/features/RumConfigurationNative.ts b/packages/core/src/config/features/RumConfigurationNative.ts index 155f086e9..aabce2403 100644 --- a/packages/core/src/config/features/RumConfigurationNative.ts +++ b/packages/core/src/config/features/RumConfigurationNative.ts @@ -3,6 +3,8 @@ * This product includes software developed at Datadog (https://www.datadoghq.com/). * Copyright 2016-Present Datadog, Inc. */ +import type { TimeseriesConfiguration } from '../types'; + export type RumNativeConfiguration = { readonly applicationId: string; readonly trackFrustrations: boolean; @@ -23,4 +25,5 @@ export type RumNativeConfiguration = { readonly telemetrySampleRate: number; readonly customEndpoint: string; readonly firstPartyHosts: { match: string; propagatorTypes: string[] }[]; + readonly timeseries: TimeseriesConfiguration | undefined; }; diff --git a/packages/core/src/config/types/TimeseriesConfiguration.ts b/packages/core/src/config/types/TimeseriesConfiguration.ts new file mode 100644 index 000000000..e78433fd9 --- /dev/null +++ b/packages/core/src/config/types/TimeseriesConfiguration.ts @@ -0,0 +1,40 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2016-Present Datadog, Inc. + */ + +/** + * Experimental: configuration for memory and CPU timeseries collection. + * Requires a native SDK build with timeseries support. + */ +export interface TimeseriesConfiguration { + /** + * Enables collection of memory and CPU timeseries events. + */ + enabled: boolean; + + /** + * The number of samples collected before a timeseries batch is flushed. + * iOS and Android only. + */ + bufferSize?: number; + + /** + * The sampling interval in milliseconds. + * Android only. + */ + intervalMs?: number; + + /** + * Whether to keep sampling timeseries when the app is in background. + * Android only. + */ + collectInBackground?: boolean; + + /** + * Whether to encode each sample as a delta from the previous value instead of an absolute value. + * Android only. + */ + useDeltaCompression?: boolean; +} diff --git a/packages/core/src/config/types/index.ts b/packages/core/src/config/types/index.ts index 6df83e28c..c43632532 100644 --- a/packages/core/src/config/types/index.ts +++ b/packages/core/src/config/types/index.ts @@ -8,6 +8,7 @@ export { BatchProcessingLevel } from './BatchProcessingLevel'; export { BatchSize } from './BatchSize'; export { ProxyConfiguration, ProxyType } from './ProxyConfiguration'; export { SdkVerbosity } from './SdkVerbosity'; +export type { TimeseriesConfiguration } from './TimeseriesConfiguration'; export { TrackingConsent } from './TrackingConsent'; export { UploadFrequency } from './UploadFrequency'; export { VitalsUpdateFrequency } from './VitalsUpdateFrequency'; From e3149324d6175c712923be0b9afb61cfe7564c63 Mon Sep 17 00:00:00 2001 From: Barbora Plasovska Date: Fri, 17 Jul 2026 13:53:23 +0200 Subject: [PATCH 2/4] RUM-17173 Bump default timeseriesBatchSize on iOS to match native's new default of 120 --- packages/core/ios/Sources/RNDdSdkConfiguration.swift | 2 +- packages/core/ios/Tests/DdSdkNativeInitializationTests.swift | 2 +- packages/core/ios/Tests/DdSdkTests.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/core/ios/Sources/RNDdSdkConfiguration.swift b/packages/core/ios/Sources/RNDdSdkConfiguration.swift index a4e06dbda..616cb6364 100644 --- a/packages/core/ios/Sources/RNDdSdkConfiguration.swift +++ b/packages/core/ios/Sources/RNDdSdkConfiguration.swift @@ -292,7 +292,7 @@ internal struct DefaultConfiguration { static let trackWatchdogTerminations = false static let trackMemoryWarnings = true static let enableTimeseries = false - static let timeseriesBatchSize = 30.0 + static let timeseriesBatchSize = 120.0 } extension Dictionary where Key == String, Value == AnyObject { diff --git a/packages/core/ios/Tests/DdSdkNativeInitializationTests.swift b/packages/core/ios/Tests/DdSdkNativeInitializationTests.swift index 577d9309b..54c6a384f 100644 --- a/packages/core/ios/Tests/DdSdkNativeInitializationTests.swift +++ b/packages/core/ios/Tests/DdSdkNativeInitializationTests.swift @@ -107,7 +107,7 @@ class DdSdkNativeInitializationTests: XCTestCase { XCTAssertEqual(configuration?.rumConfiguration?.firstPartyHosts, expectedFirstPartyHosts) XCTAssertEqual(configuration?.rumConfiguration?.initialResourceThreshold, nil) XCTAssertEqual(configuration?.rumConfiguration?.enableTimeseries, false) - XCTAssertEqual(configuration?.rumConfiguration?.timeseriesBatchSize, 30.0) + XCTAssertEqual(configuration?.rumConfiguration?.timeseriesBatchSize, 120.0) } func testPrintsMessageWithIncorrectFile() { diff --git a/packages/core/ios/Tests/DdSdkTests.swift b/packages/core/ios/Tests/DdSdkTests.swift index fedb5b811..70e7add7d 100644 --- a/packages/core/ios/Tests/DdSdkTests.swift +++ b/packages/core/ios/Tests/DdSdkTests.swift @@ -1074,7 +1074,7 @@ class DdSdkTests: XCTestCase { ) XCTAssertEqual(ddConfig.enableTimeseries, false) - XCTAssertEqual(ddConfig.timeseriesBatchSize, 30) + XCTAssertEqual(ddConfig.timeseriesBatchSize, 120) } func testBuildConfigurationAverageUploadFrequency() { From 1a0b9cfd309f95f42e4c3ef526f2d33f67da05c6 Mon Sep 17 00:00:00 2001 From: Barbora Plasovska Date: Fri, 17 Jul 2026 14:25:23 +0200 Subject: [PATCH 3/4] RUM-17173 Remove useDeltaCompression and collectInBackground from timeseries config on Android --- .../com/datadog/reactnative/DdSdkConfiguration.kt | 10 ++-------- .../com/datadog/reactnative/DdSdkConfigurationExt.kt | 10 ++-------- .../datadog/reactnative/DdSdkNativeInitialization.kt | 2 -- .../com/datadog/tools/unit/DdSdkConfigurationExt.kt | 10 ++++++++++ packages/core/datadog-configuration.schema.json | 8 -------- .../core/src/config/types/TimeseriesConfiguration.ts | 12 ------------ 6 files changed, 14 insertions(+), 38 deletions(-) diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfiguration.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfiguration.kt index a03ce2d96..48a7a27a0 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfiguration.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfiguration.kt @@ -94,15 +94,11 @@ data class RumConfiguration( * @param enabled Enables collection of memory and CPU timeseries events. * @param bufferSize The number of samples collected before a timeseries batch is flushed. * @param intervalMs The sampling interval in milliseconds. - * @param collectInBackground Whether to keep sampling timeseries when the app is in background. - * @param useDeltaCompression Whether to encode each sample as a delta from the previous value instead of an absolute value. */ data class TimeseriesConfiguration( val enabled: Boolean, val bufferSize: Double? = null, - val intervalMs: Double? = null, - val collectInBackground: Boolean? = null, - val useDeltaCompression: Boolean? = null + val intervalMs: Double? = null ) /** @@ -184,9 +180,7 @@ internal data class JSONRumConfiguration( internal data class JSONTimeseriesConfiguration( val enabled: Boolean? = null, val bufferSize: Double? = null, - val intervalMs: Double? = null, - val collectInBackground: Boolean? = null, - val useDeltaCompression: Boolean? = null + val intervalMs: Double? = null ) internal data class JSONLogsConfiguration( diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfigurationExt.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfigurationExt.kt index ebd041d68..7aa6b754d 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfigurationExt.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkConfigurationExt.kt @@ -91,9 +91,7 @@ internal fun ReadableMap.asTimeseriesConfiguration(): TimeseriesConfiguration { return TimeseriesConfiguration( enabled = getBooleanOrNull("enabled") ?: false, bufferSize = getDoubleOrNull("bufferSize"), - intervalMs = getDoubleOrNull("intervalMs"), - collectInBackground = getBooleanOrNull("collectInBackground"), - useDeltaCompression = getBooleanOrNull("useDeltaCompression") + intervalMs = getDoubleOrNull("intervalMs") ) } @@ -245,9 +243,7 @@ internal fun JSONTimeseriesConfiguration.asTimeseriesConfiguration(): Timeseries return TimeseriesConfiguration( enabled = this.enabled ?: false, bufferSize = this.bufferSize, - intervalMs = this.intervalMs, - collectInBackground = this.collectInBackground, - useDeltaCompression = this.useDeltaCompression + intervalMs = this.intervalMs ) } @@ -358,8 +354,6 @@ internal fun DdSdkConfiguration.toReadableMap(): ReadableMap { timeseriesMap.putBoolean("enabled", timeseries.enabled) timeseries.bufferSize?.let { timeseriesMap.putDouble("bufferSize", it) } timeseries.intervalMs?.let { timeseriesMap.putDouble("intervalMs", it) } - timeseries.collectInBackground?.let { timeseriesMap.putBoolean("collectInBackground", it) } - timeseries.useDeltaCompression?.let { timeseriesMap.putBoolean("useDeltaCompression", it) } rumMap.putMap("timeseries", timeseriesMap) } diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkNativeInitialization.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkNativeInitialization.kt index 1ba3ec82f..8e92e111a 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkNativeInitialization.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdSdkNativeInitialization.kt @@ -277,8 +277,6 @@ class DdSdkNativeInitialization internal constructor( val nativeConfigBuilder = NativeTimeseriesConfiguration.Builder() timeseries.bufferSize?.let { nativeConfigBuilder.setBufferSize(it.toInt()) } timeseries.intervalMs?.let { nativeConfigBuilder.setIntervalMs(it.toLong()) } - timeseries.collectInBackground?.let { nativeConfigBuilder.collectInBackground(it) } - timeseries.useDeltaCompression?.let { nativeConfigBuilder.useDeltaCompression(it) } configBuilder.setTimeseriesConfiguration(nativeConfigBuilder.build()) } diff --git a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/DdSdkConfigurationExt.kt b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/DdSdkConfigurationExt.kt index 4fc6c96d6..1280b40a2 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/DdSdkConfigurationExt.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/DdSdkConfigurationExt.kt @@ -13,6 +13,7 @@ import com.datadog.android.rum.configuration.VitalsUpdateFrequency import com.datadog.reactnative.ConfigurationForTelemetry import com.datadog.reactnative.DdSdkConfiguration import com.datadog.reactnative.ProxyAuthenticator +import com.datadog.reactnative.TimeseriesConfiguration import com.facebook.react.bridge.ReadableMap import java.net.Proxy @@ -67,6 +68,7 @@ fun DdSdkConfiguration.toReadableJavaOnlyMap(): ReadableMap { rumMap["initialResourceThreshold"] = rum?.initialResourceThreshold ?: 0.1 rumMap["telemetrySampleRate"] = rum?.telemetrySampleRate ?: 20.0 rum?.customEndpoint?.let { rumMap["customEndpoint"] = it } + rum?.timeseries?.let { rumMap["timeseries"] = it.toReadableMap() } map["rumConfiguration"] = rumMap.toReadableMap() } @@ -93,6 +95,14 @@ fun DdSdkConfiguration.toReadableJavaOnlyMap(): ReadableMap { return map.toReadableMap() } +internal fun TimeseriesConfiguration.toReadableMap(): ReadableMap { + val map = mutableMapOf() + map["enabled"] = enabled + bufferSize?.let { map["bufferSize"] = it } + intervalMs?.let { map["intervalMs"] = it } + return map.toReadableMap() +} + internal fun ConfigurationForTelemetry.toReadableJavaOnlyMap(): ReadableMap { val map = mutableMapOf() initializationType?.let { map.put("initializationType", it) } diff --git a/packages/core/datadog-configuration.schema.json b/packages/core/datadog-configuration.schema.json index 63c92d6c3..43e55c17c 100644 --- a/packages/core/datadog-configuration.schema.json +++ b/packages/core/datadog-configuration.schema.json @@ -278,14 +278,6 @@ "intervalMs": { "description": "The sampling interval in milliseconds. Android only.", "type": "integer" - }, - "collectInBackground": { - "description": "Whether to keep sampling timeseries when the app is in background. Android only.", - "type": "boolean" - }, - "useDeltaCompression": { - "description": "Whether to encode each sample as a delta from the previous value instead of an absolute value. Android only.", - "type": "boolean" } }, "required": [ diff --git a/packages/core/src/config/types/TimeseriesConfiguration.ts b/packages/core/src/config/types/TimeseriesConfiguration.ts index e78433fd9..12615b984 100644 --- a/packages/core/src/config/types/TimeseriesConfiguration.ts +++ b/packages/core/src/config/types/TimeseriesConfiguration.ts @@ -25,16 +25,4 @@ export interface TimeseriesConfiguration { * Android only. */ intervalMs?: number; - - /** - * Whether to keep sampling timeseries when the app is in background. - * Android only. - */ - collectInBackground?: boolean; - - /** - * Whether to encode each sample as a delta from the previous value instead of an absolute value. - * Android only. - */ - useDeltaCompression?: boolean; } From a7658c84d9038f52c5b855b8a7d383b809adfe75 Mon Sep 17 00:00:00 2001 From: Barbora Plasovska Date: Thu, 23 Jul 2026 16:04:47 +0200 Subject: [PATCH 4/4] RUM-17173 Update default-config snapshot for new timeseries field --- .../src/sdk/DatadogProvider/__tests__/initialization.test.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/src/sdk/DatadogProvider/__tests__/initialization.test.tsx b/packages/core/src/sdk/DatadogProvider/__tests__/initialization.test.tsx index 1380fb0c2..0411aaa39 100644 --- a/packages/core/src/sdk/DatadogProvider/__tests__/initialization.test.tsx +++ b/packages/core/src/sdk/DatadogProvider/__tests__/initialization.test.tsx @@ -102,6 +102,7 @@ describe('DatadogProvider', () => { "resourceTraceSampleRate": 100, "sessionSampleRate": 100, "telemetrySampleRate": 20, + "timeseries": undefined, "trackBackgroundEvents": false, "trackErrors": true, "trackFrustrations": true,