Skip to content

Commit fd55c46

Browse files
authored
Merge pull request #2828 from DataDog/tvaleev/feature/RUM-11251-fix-serialization
[RUM-11251][FO]: Fix RumVitalEvent serialization logic
2 parents ef04491 + c1101c6 commit fd55c46

File tree

14 files changed

+414
-1
lines changed

14 files changed

+414
-1
lines changed

features/dd-sdk-android-rum/api/apiSurface

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ data class com.datadog.android.rum.RumConfiguration
8282
fun setActionEventMapper(com.datadog.android.event.EventMapper<com.datadog.android.rum.model.ActionEvent>): Builder
8383
fun setErrorEventMapper(com.datadog.android.event.EventMapper<com.datadog.android.rum.model.ErrorEvent>): Builder
8484
fun setLongTaskEventMapper(com.datadog.android.event.EventMapper<com.datadog.android.rum.model.LongTaskEvent>): Builder
85+
fun setVitalEventMapper(com.datadog.android.event.EventMapper<com.datadog.android.rum.model.RumVitalEvent>): Builder
8586
fun trackBackgroundEvents(Boolean): Builder
8687
fun trackFrustrations(Boolean): Builder
8788
fun setVitalsUpdateFrequency(com.datadog.android.rum.configuration.VitalsUpdateFrequency): Builder

features/dd-sdk-android-rum/api/dd-sdk-android-rum.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ public final class com/datadog/android/rum/RumConfiguration$Builder {
117117
public final fun setSlowFramesConfiguration (Lcom/datadog/android/rum/configuration/SlowFramesConfiguration;)Lcom/datadog/android/rum/RumConfiguration$Builder;
118118
public final fun setTelemetrySampleRate (F)Lcom/datadog/android/rum/RumConfiguration$Builder;
119119
public final fun setViewEventMapper (Lcom/datadog/android/rum/event/ViewEventMapper;)Lcom/datadog/android/rum/RumConfiguration$Builder;
120+
public final fun setVitalEventMapper (Lcom/datadog/android/event/EventMapper;)Lcom/datadog/android/rum/RumConfiguration$Builder;
120121
public final fun setVitalsUpdateFrequency (Lcom/datadog/android/rum/configuration/VitalsUpdateFrequency;)Lcom/datadog/android/rum/RumConfiguration$Builder;
121122
public final fun trackAnonymousUser (Z)Lcom/datadog/android/rum/RumConfiguration$Builder;
122123
public final fun trackBackgroundEvents (Z)Lcom/datadog/android/rum/RumConfiguration$Builder;

features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/RumConfiguration.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import com.datadog.android.rum.model.ActionEvent
2222
import com.datadog.android.rum.model.ErrorEvent
2323
import com.datadog.android.rum.model.LongTaskEvent
2424
import com.datadog.android.rum.model.ResourceEvent
25+
import com.datadog.android.rum.model.RumVitalEvent
2526
import com.datadog.android.rum.model.ViewEvent
2627
import com.datadog.android.rum.tracking.ActionTrackingStrategy
2728
import com.datadog.android.rum.tracking.ActivityViewTrackingStrategy
@@ -219,6 +220,17 @@ data class RumConfiguration internal constructor(
219220
return this
220221
}
221222

223+
/**
224+
* Sets the [EventMapper] for the RUM [RumVitalEvent]. You can use this interface implementation
225+
* to modify the [RumVitalEvent] attributes before serialisation.
226+
*
227+
* @param eventMapper the [EventMapper] implementation.
228+
*/
229+
fun setVitalEventMapper(eventMapper: EventMapper<RumVitalEvent>): Builder {
230+
rumConfig = rumConfig.copy(vitalEventMapper = eventMapper)
231+
return this
232+
}
233+
222234
/**
223235
* Enables/Disables tracking RUM event when no Activity is in foreground.
224236
*

features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/RumFeature.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ import com.datadog.android.rum.model.ActionEvent
9090
import com.datadog.android.rum.model.ErrorEvent
9191
import com.datadog.android.rum.model.LongTaskEvent
9292
import com.datadog.android.rum.model.ResourceEvent
93+
import com.datadog.android.rum.model.RumVitalEvent
9394
import com.datadog.android.rum.model.ViewEvent
9495
import com.datadog.android.rum.tracking.ActionTrackingStrategy
9596
import com.datadog.android.rum.tracking.ActivityViewTrackingStrategy
@@ -329,6 +330,7 @@ internal class RumFeature(
329330
resourceEventMapper = configuration.resourceEventMapper,
330331
actionEventMapper = configuration.actionEventMapper,
331332
longTaskEventMapper = configuration.longTaskEventMapper,
333+
vitalEventMapper = configuration.vitalEventMapper,
332334
telemetryConfigurationMapper = configuration.telemetryConfigurationMapper,
333335
internalLogger = sdkCore.internalLogger
334336
),
@@ -641,6 +643,7 @@ internal class RumFeature(
641643
val resourceEventMapper: EventMapper<ResourceEvent>,
642644
val actionEventMapper: EventMapper<ActionEvent>,
643645
val longTaskEventMapper: EventMapper<LongTaskEvent>,
646+
val vitalEventMapper: EventMapper<RumVitalEvent>,
644647
val telemetryConfigurationMapper: EventMapper<TelemetryConfigurationEvent>,
645648
val backgroundEventTracking: Boolean,
646649
val trackFrustrations: Boolean,
@@ -692,6 +695,7 @@ internal class RumFeature(
692695
resourceEventMapper = NoOpEventMapper(),
693696
actionEventMapper = NoOpEventMapper(),
694697
longTaskEventMapper = NoOpEventMapper(),
698+
vitalEventMapper = NoOpEventMapper(),
695699
telemetryConfigurationMapper = NoOpEventMapper(),
696700
backgroundEventTracking = false,
697701
trackFrustrations = true,

features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapper.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import com.datadog.android.rum.model.ActionEvent
1313
import com.datadog.android.rum.model.ErrorEvent
1414
import com.datadog.android.rum.model.LongTaskEvent
1515
import com.datadog.android.rum.model.ResourceEvent
16+
import com.datadog.android.rum.model.RumVitalEvent
1617
import com.datadog.android.rum.model.ViewEvent
1718
import com.datadog.android.telemetry.model.TelemetryConfigurationEvent
1819
import com.datadog.android.telemetry.model.TelemetryDebugEvent
@@ -26,6 +27,7 @@ internal data class RumEventMapper(
2627
val resourceEventMapper: EventMapper<ResourceEvent> = NoOpEventMapper(),
2728
val actionEventMapper: EventMapper<ActionEvent> = NoOpEventMapper(),
2829
val longTaskEventMapper: EventMapper<LongTaskEvent> = NoOpEventMapper(),
30+
val vitalEventMapper: EventMapper<RumVitalEvent> = NoOpEventMapper(),
2931
val telemetryConfigurationMapper: EventMapper<TelemetryConfigurationEvent> = NoOpEventMapper(),
3032
private val internalLogger: InternalLogger
3133
) : EventMapper<Any> {
@@ -60,6 +62,7 @@ internal data class RumEventMapper(
6062
}
6163
is ResourceEvent -> resourceEventMapper.map(event)
6264
is LongTaskEvent -> longTaskEventMapper.map(event)
65+
is RumVitalEvent -> vitalEventMapper.map(event)
6366
is TelemetryConfigurationEvent -> telemetryConfigurationMapper.map(event)
6467
is TelemetryDebugEvent,
6568
is TelemetryUsageEvent,

features/dd-sdk-android-rum/src/main/kotlin/com/datadog/android/rum/internal/domain/event/RumEventSerializer.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import com.datadog.android.rum.model.ActionEvent
1616
import com.datadog.android.rum.model.ErrorEvent
1717
import com.datadog.android.rum.model.LongTaskEvent
1818
import com.datadog.android.rum.model.ResourceEvent
19+
import com.datadog.android.rum.model.RumVitalEvent
1920
import com.datadog.android.rum.model.ViewEvent
2021
import com.datadog.android.telemetry.model.TelemetryConfigurationEvent
2122
import com.datadog.android.telemetry.model.TelemetryDebugEvent
@@ -47,6 +48,9 @@ internal class RumEventSerializer(
4748
is LongTaskEvent -> {
4849
serializeLongTaskEvent(model)
4950
}
51+
is RumVitalEvent -> {
52+
serializeVitalEvent(model)
53+
}
5054
is TelemetryDebugEvent -> {
5155
model.toJson().toString()
5256
}
@@ -201,6 +205,30 @@ internal class RumEventSerializer(
201205
return extractKnownAttributes(sanitizedModel.toJson().asJsonObject).toString()
202206
}
203207

208+
private fun serializeVitalEvent(model: RumVitalEvent): String {
209+
val sanitizedUser = model.usr?.copy(
210+
additionalProperties = validateUserAttributes(model.usr.additionalProperties)
211+
.safeMapValuesToJson(internalLogger)
212+
.toMutableMap()
213+
)
214+
val sanitizedAccount = model.account?.copy(
215+
additionalProperties = validateAccountAttributes(model.account.additionalProperties)
216+
.safeMapValuesToJson(internalLogger)
217+
.toMutableMap()
218+
)
219+
val sanitizedContext = model.context?.copy(
220+
additionalProperties = validateContextAttributes(model.context.additionalProperties)
221+
.safeMapValuesToJson(internalLogger)
222+
.toMutableMap()
223+
)
224+
val sanitizedModel = model.copy(
225+
usr = sanitizedUser,
226+
account = sanitizedAccount,
227+
context = sanitizedContext
228+
)
229+
return extractKnownAttributes(sanitizedModel.toJson().asJsonObject).toString()
230+
}
231+
204232
private fun validateContextAttributes(attributes: Map<String, Any?>): MutableMap<String, Any?> {
205233
return dataConstraints.validateAttributes(
206234
attributes.filterKeys {

features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/RumConfigurationBuilderTest.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.datadog.android.rum.model.ActionEvent
2525
import com.datadog.android.rum.model.ErrorEvent
2626
import com.datadog.android.rum.model.LongTaskEvent
2727
import com.datadog.android.rum.model.ResourceEvent
28+
import com.datadog.android.rum.model.RumVitalEvent
2829
import com.datadog.android.rum.model.ViewEvent
2930
import com.datadog.android.rum.tracking.ActionTrackingStrategy
3031
import com.datadog.android.rum.tracking.ActivityViewTrackingStrategy
@@ -448,6 +449,24 @@ internal class RumConfigurationBuilderTest {
448449
)
449450
}
450451

452+
@Test
453+
fun `M build config with RUM Vital eventMapper W seVitalEventMapper() & build()`() {
454+
// Given
455+
val eventMapper: EventMapper<RumVitalEvent> = mock()
456+
457+
// When
458+
val rumConfiguration = testedBuilder
459+
.setVitalEventMapper(eventMapper)
460+
.build()
461+
462+
// Then
463+
assertThat(rumConfiguration.featureConfiguration).isEqualTo(
464+
RumFeature.DEFAULT_RUM_CONFIG.copy(
465+
vitalEventMapper = eventMapper
466+
)
467+
)
468+
}
469+
451470
@Test
452471
fun `M use the given frequency W setVitalsMonitorUpdateFrequency`(
453472
@Forgery fakeFrequency: VitalsUpdateFrequency

features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/domain/event/RumEventMapperTest.kt

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import com.datadog.android.rum.model.ActionEvent
1212
import com.datadog.android.rum.model.ErrorEvent
1313
import com.datadog.android.rum.model.LongTaskEvent
1414
import com.datadog.android.rum.model.ResourceEvent
15+
import com.datadog.android.rum.model.RumVitalEvent
1516
import com.datadog.android.rum.model.ViewEvent
1617
import com.datadog.android.rum.utils.forge.Configurator
1718
import com.datadog.android.rum.utils.forge.aRumEvent
@@ -64,6 +65,9 @@ internal class RumEventMapperTest {
6465
@Mock
6566
lateinit var mockLongTaskEventMapper: EventMapper<LongTaskEvent>
6667

68+
@Mock
69+
lateinit var mockVitalEventMapper: EventMapper<RumVitalEvent>
70+
6771
@Mock
6872
lateinit var mockTelemetryConfigurationMapper: EventMapper<TelemetryConfigurationEvent>
6973

@@ -80,6 +84,7 @@ internal class RumEventMapperTest {
8084
resourceEventMapper = mockResourceEventMapper,
8185
errorEventMapper = mockErrorEventMapper,
8286
longTaskEventMapper = mockLongTaskEventMapper,
87+
vitalEventMapper = mockVitalEventMapper,
8388
telemetryConfigurationMapper = mockTelemetryConfigurationMapper,
8489
internalLogger = mockInternalLogger
8590
)
@@ -172,6 +177,20 @@ internal class RumEventMapperTest {
172177
assertThat(mappedRumEvent).isEqualTo(fakeRumEvent)
173178
}
174179

180+
@Test
181+
fun `M map the bundled event W map { RumVitalEvent }`(forge: Forge) {
182+
// GIVEN
183+
val fakeRumEvent = forge.getForgery<RumVitalEvent>()
184+
whenever(mockVitalEventMapper.map(fakeRumEvent)).thenReturn(fakeRumEvent)
185+
186+
// WHEN
187+
val mappedRumEvent = testedRumEventMapper.map(fakeRumEvent)
188+
189+
// THEN
190+
assertThat(mappedRumEvent).isNotNull
191+
assertThat(mappedRumEvent).isEqualTo(fakeRumEvent)
192+
}
193+
175194
@Test
176195
fun `M return the original event W map { no internal mapper used }`(forge: Forge) {
177196
// GIVEN
@@ -387,6 +406,26 @@ internal class RumEventMapperTest {
387406
)
388407
}
389408

409+
@Test
410+
fun `M return null event W map returns null object { RumVitalEvent }`(forge: Forge) {
411+
// GIVEN
412+
val fakeRumEvent = forge.getForgery<RumVitalEvent>()
413+
whenever(mockVitalEventMapper.map(fakeRumEvent))
414+
.thenReturn(null)
415+
416+
// WHEN
417+
val mappedRumEvent = testedRumEventMapper.map(fakeRumEvent)
418+
419+
// THEN
420+
assertThat(mappedRumEvent).isNull()
421+
mockInternalLogger.verifyLog(
422+
InternalLogger.Level.INFO,
423+
InternalLogger.Target.USER,
424+
RumEventMapper.EVENT_NULL_WARNING_MESSAGE.format(Locale.US, fakeRumEvent)
425+
426+
)
427+
}
428+
390429
@Test
391430
fun `M use the original event W map returns different object { ViewEvent }`(forge: Forge) {
392431
// GIVEN
@@ -491,6 +530,26 @@ internal class RumEventMapperTest {
491530
)
492531
}
493532

533+
@Test
534+
fun `M return null event W map returns different object { RumVitalEvent }`(forge: Forge) {
535+
// GIVEN
536+
val fakeRumEvent = forge.getForgery<RumVitalEvent>()
537+
whenever(mockVitalEventMapper.map(fakeRumEvent))
538+
.thenReturn(forge.getForgery())
539+
540+
// WHEN
541+
val mappedRumEvent = testedRumEventMapper.map(fakeRumEvent)
542+
543+
// THEN
544+
assertThat(mappedRumEvent).isNull()
545+
mockInternalLogger.verifyLog(
546+
InternalLogger.Level.WARN,
547+
InternalLogger.Target.USER,
548+
RumEventMapper.NOT_SAME_EVENT_INSTANCE_WARNING_MESSAGE.format(Locale.US, fakeRumEvent)
549+
550+
)
551+
}
552+
494553
@Test
495554
fun `M use the original event W map returns a copy { ViewEvent }`(forge: Forge) {
496555
// GIVEN
@@ -593,4 +652,24 @@ internal class RumEventMapperTest {
593652

594653
)
595654
}
655+
656+
@Test
657+
fun `M return null event W map returns a copy { RumVitalEvent }`(forge: Forge) {
658+
// GIVEN
659+
val fakeRumEvent = forge.getForgery<RumVitalEvent>()
660+
whenever(mockVitalEventMapper.map(fakeRumEvent))
661+
.thenReturn(fakeRumEvent.copy())
662+
663+
// WHEN
664+
val mappedRumEvent = testedRumEventMapper.map(fakeRumEvent)
665+
666+
// THEN
667+
assertThat(mappedRumEvent).isNull()
668+
mockInternalLogger.verifyLog(
669+
InternalLogger.Level.WARN,
670+
InternalLogger.Target.USER,
671+
RumEventMapper.NOT_SAME_EVENT_INSTANCE_WARNING_MESSAGE.format(Locale.US, fakeRumEvent)
672+
673+
)
674+
}
596675
}

0 commit comments

Comments
 (0)