Skip to content

Commit 36f6fe1

Browse files
RUM-13075: Do not send TTID and TTFD if they are larger than 1 minute
1 parent 23e8d2b commit 36f6fe1

File tree

2 files changed

+191
-16
lines changed

2 files changed

+191
-16
lines changed

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

Lines changed: 68 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import com.datadog.android.rum.internal.domain.scope.RumRawEvent
1616
import com.datadog.android.rum.internal.domain.scope.RumVitalAppLaunchEventHelper
1717
import com.datadog.android.rum.internal.utils.newRumEventWriteOperation
1818
import com.datadog.android.rum.model.RumVitalAppLaunchEvent
19+
import kotlin.time.Duration.Companion.minutes
1920

2021
internal interface RumSessionScopeStartupManager {
2122
fun onAppStartEvent(event: RumRawEvent.AppStartEvent)
@@ -99,19 +100,14 @@ internal class RumSessionScopeStartupManagerImpl(
99100

100101
ttidSentForSession = true
101102

102-
sdkCore.newRumEventWriteOperation(datadogContext, writeScope, writer) {
103-
rumVitalAppLaunchEventHelper.newVitalAppLaunchEvent(
104-
timestampMs = event.info.scenario.initialTime.timestamp + sdkCore.time.serverTimeOffsetMs,
105-
datadogContext = datadogContext,
106-
eventAttributes = emptyMap(),
107-
customAttributes = customAttributes,
108-
hasReplay = null,
109-
rumContext = rumContext,
110-
durationNs = event.info.durationNs,
111-
appLaunchMetric = RumVitalAppLaunchEvent.AppLaunchMetric.TTID,
112-
scenario = event.info.scenario
113-
)
114-
}.submit()
103+
sendTTIDEvent(
104+
datadogContext = datadogContext,
105+
writeScope = writeScope,
106+
writer = writer,
107+
rumContext = rumContext,
108+
customAttributes = customAttributes,
109+
event = event
110+
)
115111

116112
if (ttfdReportedForScenario) {
117113
/**
@@ -197,6 +193,20 @@ internal class RumSessionScopeStartupManagerImpl(
197193
durationNs: Long,
198194
scenario: RumStartupScenario
199195
) {
196+
if (durationNs > DURATION_SUITABLE_TO_REPORT_THRESHOLD) {
197+
sdkCore.internalLogger.log(
198+
level = InternalLogger.Level.WARN,
199+
target = InternalLogger.Target.USER,
200+
messageBuilder = {
201+
TTFD_TOO_LARGE_MESSAGE
202+
},
203+
throwable = null,
204+
onlyOnce = false,
205+
additionalProperties = null
206+
)
207+
return
208+
}
209+
200210
sdkCore.newRumEventWriteOperation(datadogContext, writeScope, writer) {
201211
rumVitalAppLaunchEventHelper.newVitalAppLaunchEvent(
202212
timestampMs = scenario.initialTime.timestamp + sdkCore.time.serverTimeOffsetMs,
@@ -212,11 +222,56 @@ internal class RumSessionScopeStartupManagerImpl(
212222
}.submit()
213223
}
214224

225+
private fun sendTTIDEvent(
226+
datadogContext: DatadogContext,
227+
writeScope: EventWriteScope,
228+
writer: DataWriter<Any>,
229+
rumContext: RumContext,
230+
customAttributes: Map<String, Any?>,
231+
event: RumRawEvent.AppStartTTIDEvent
232+
) {
233+
val durationNs = event.info.durationNs
234+
235+
if (durationNs > DURATION_SUITABLE_TO_REPORT_THRESHOLD) {
236+
sdkCore.internalLogger.log(
237+
level = InternalLogger.Level.WARN,
238+
target = InternalLogger.Target.USER,
239+
messageBuilder = {
240+
TTID_TOO_LARGE_MESSAGE
241+
},
242+
throwable = null,
243+
onlyOnce = false,
244+
additionalProperties = null
245+
)
246+
return
247+
}
248+
249+
sdkCore.newRumEventWriteOperation(datadogContext, writeScope, writer) {
250+
rumVitalAppLaunchEventHelper.newVitalAppLaunchEvent(
251+
timestampMs = event.info.scenario.initialTime.timestamp + sdkCore.time.serverTimeOffsetMs,
252+
datadogContext = datadogContext,
253+
eventAttributes = emptyMap(),
254+
customAttributes = customAttributes,
255+
hasReplay = null,
256+
rumContext = rumContext,
257+
durationNs = durationNs,
258+
appLaunchMetric = RumVitalAppLaunchEvent.AppLaunchMetric.TTID,
259+
scenario = event.info.scenario
260+
)
261+
}.submit()
262+
}
263+
215264
companion object {
216265
internal const val REPORT_APP_FULLY_DISPLAYED_CALLED_TOO_EARLY_MESSAGE =
217266
"RumMonitor.reportAppFullyDisplayed was called before the application launch was detected, ignoring it."
218267

219268
internal const val REPORT_APP_FULLY_DISPLAYED_CALLED_BEFORE_TTID_MESSAGE =
220269
"RumMonitor.reportAppFullyDisplayed was called before TTID was computed, will report TTID as TTFD."
270+
271+
internal const val TTID_TOO_LARGE_MESSAGE = "TTID value is too large, skipping it"
272+
273+
internal const val TTFD_TOO_LARGE_MESSAGE = "TTFD value is too large, skipping it"
274+
275+
internal val DURATION_SUITABLE_TO_REPORT_THRESHOLD: Long = 1.minutes.inWholeNanoseconds
221276
}
222277
}

features/dd-sdk-android-rum/src/test/kotlin/com/datadog/android/rum/internal/startup/RumSessionScopeStartupManagerTest.kt

Lines changed: 123 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import com.datadog.android.rum.assertj.VitalAppLaunchEventAssert
2020
import com.datadog.android.rum.assertj.VitalAppLaunchPropertiesAssert.Companion.assertThat
2121
import com.datadog.android.rum.internal.domain.InfoProvider
2222
import com.datadog.android.rum.internal.domain.RumContext
23+
import com.datadog.android.rum.internal.domain.Time
2324
import com.datadog.android.rum.internal.domain.battery.BatteryInfo
2425
import com.datadog.android.rum.internal.domain.display.DisplayInfo
2526
import com.datadog.android.rum.internal.domain.scope.RumRawEvent
@@ -53,6 +54,7 @@ import org.mockito.junit.jupiter.MockitoExtension
5354
import org.mockito.junit.jupiter.MockitoSettings
5455
import org.mockito.kotlin.any
5556
import org.mockito.kotlin.argumentCaptor
57+
import org.mockito.kotlin.atLeastOnce
5658
import org.mockito.kotlin.doAnswer
5759
import org.mockito.kotlin.doReturn
5860
import org.mockito.kotlin.eq
@@ -64,6 +66,7 @@ import org.mockito.kotlin.verifyNoMoreInteractions
6466
import org.mockito.kotlin.whenever
6567
import org.mockito.quality.Strictness
6668
import java.lang.ref.WeakReference
69+
import java.util.concurrent.TimeUnit
6770
import java.util.stream.Stream
6871

6972
@Extensions(
@@ -309,7 +312,7 @@ internal class RumSessionScopeStartupManagerTest {
309312

310313
val ttidEvent = RumRawEvent.AppStartTTIDEvent(info = info)
311314

312-
val ttfdEvent = RumRawEvent.AppStartTTFDEvent()
315+
val ttfdEvent = forge.createTTFDEvent(scenario.initialTime)
313316

314317
// When
315318
manager.onAppStartEvent(RumRawEvent.AppStartEvent(scenario = scenario))
@@ -371,8 +374,8 @@ internal class RumSessionScopeStartupManagerTest {
371374
val ttidEvent1 = RumRawEvent.AppStartTTIDEvent(info = info1)
372375
val ttidEvent2 = RumRawEvent.AppStartTTIDEvent(info = info2)
373376

374-
val ttfdEvent1 = RumRawEvent.AppStartTTFDEvent()
375-
val ttfdEvent2 = RumRawEvent.AppStartTTFDEvent()
377+
val ttfdEvent1 = forge.createTTFDEvent(scenario1.initialTime)
378+
val ttfdEvent2 = forge.createTTFDEvent(scenario2.initialTime)
376379

377380
// When
378381
manager.onAppStartEvent(appStartEvent1)
@@ -545,6 +548,109 @@ internal class RumSessionScopeStartupManagerTest {
545548
}
546549
}
547550

551+
@ParameterizedTest
552+
@MethodSource("testScenarios")
553+
fun `M not send TTID vital event W onTTIDEvent { duration is too large }`(
554+
scenario: RumStartupScenario,
555+
forge: Forge
556+
) {
557+
// Given
558+
val info = RumTTIDInfo(
559+
scenario = scenario,
560+
durationNs = forge.aLong(
561+
min = RumSessionScopeStartupManagerImpl.DURATION_SUITABLE_TO_REPORT_THRESHOLD + 1
562+
)
563+
)
564+
565+
val ttidEvent = RumRawEvent.AppStartTTIDEvent(
566+
info = info
567+
)
568+
569+
// When
570+
manager.onAppStartEvent(RumRawEvent.AppStartEvent(scenario = scenario))
571+
572+
manager.onTTIDEvent(
573+
event = ttidEvent,
574+
datadogContext = fakeDatadogContext,
575+
writeScope = mockEventWriteScope,
576+
writer = mockWriter,
577+
rumContext = rumContext,
578+
customAttributes = fakeParentAttributes
579+
)
580+
581+
// Then
582+
verifyNoInteractions(mockWriter)
583+
584+
mockInternalLogger.verifyLog(
585+
level = InternalLogger.Level.WARN,
586+
target = InternalLogger.Target.USER,
587+
message = RumSessionScopeStartupManagerImpl.TTID_TOO_LARGE_MESSAGE,
588+
throwable = null,
589+
onlyOnce = false,
590+
additionalProperties = null
591+
)
592+
}
593+
594+
@ParameterizedTest
595+
@MethodSource("testScenarios")
596+
fun `M not send TTFD vital event W onTTFDEvent { duration is too large }`(
597+
scenario: RumStartupScenario,
598+
forge: Forge
599+
) {
600+
// Given
601+
val info = RumTTIDInfo(
602+
scenario = scenario,
603+
durationNs = forge.aLong(min = 0, max = 10000)
604+
)
605+
606+
val ttidEvent = RumRawEvent.AppStartTTIDEvent(info = info)
607+
608+
val ttfdEvent = forge.createTTFDEvent(
609+
initialTime = scenario.initialTime,
610+
offsetNs = RumSessionScopeStartupManagerImpl.DURATION_SUITABLE_TO_REPORT_THRESHOLD + 1
611+
)
612+
613+
// When
614+
manager.onAppStartEvent(RumRawEvent.AppStartEvent(scenario = scenario))
615+
616+
manager.onTTIDEvent(
617+
event = ttidEvent,
618+
datadogContext = fakeDatadogContext,
619+
writeScope = mockEventWriteScope,
620+
writer = mockWriter,
621+
rumContext = rumContext,
622+
customAttributes = fakeParentAttributes
623+
)
624+
625+
manager.onTTFDEvent(
626+
event = ttfdEvent,
627+
datadogContext = fakeDatadogContext,
628+
writeScope = mockEventWriteScope,
629+
writer = mockWriter,
630+
rumContext = rumContext,
631+
customAttributes = fakeParentAttributes
632+
)
633+
634+
// Then
635+
inOrder(mockWriter) {
636+
argumentCaptor<RumVitalAppLaunchEvent> {
637+
verify(mockWriter, times(1)).write(eq(mockEventBatchWriter), capture(), eq(EventType.DEFAULT))
638+
verifyTTID(value = firstValue, info = info)
639+
}
640+
verifyNoMoreInteractions()
641+
}
642+
643+
mockInternalLogger.verifyLog(
644+
level = InternalLogger.Level.WARN,
645+
target = InternalLogger.Target.USER,
646+
message = RumSessionScopeStartupManagerImpl.TTFD_TOO_LARGE_MESSAGE,
647+
throwable = null,
648+
onlyOnce = false,
649+
additionalProperties = null,
650+
mode = atLeastOnce()
651+
)
652+
}
653+
548654
private fun verifyTTID(value: RumVitalAppLaunchEvent, info: RumTTIDInfo) {
549655
VitalAppLaunchEventAssert.assertThat(value).apply {
550656
hasDate(info.scenario.initialTime.timestamp + fakeTimeInfo.serverTimeOffsetMs)
@@ -680,4 +786,18 @@ internal class RumSessionScopeStartupManagerTest {
680786
.stream()
681787
}
682788
}
789+
790+
private fun Forge.createTTFDEvent(
791+
initialTime: Time,
792+
offsetNs: Long = aLong(min = 0, max = 10000)
793+
): RumRawEvent.AppStartTTFDEvent {
794+
val offsetMs = TimeUnit.NANOSECONDS.toMillis(offsetNs)
795+
796+
return RumRawEvent.AppStartTTFDEvent(
797+
eventTime = Time(
798+
timestamp = initialTime.timestamp + offsetMs,
799+
nanoTime = initialTime.nanoTime + offsetNs
800+
)
801+
)
802+
}
683803
}

0 commit comments

Comments
 (0)