Skip to content

Commit

Permalink
RUM-4084 remove browser replay info if SR disabled in app
Browse files Browse the repository at this point in the history
  • Loading branch information
xgouchet committed Apr 17, 2024
1 parent 0401e37 commit f9f810a
Show file tree
Hide file tree
Showing 6 changed files with 450 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.datadog.android.api.feature.Feature
import com.datadog.android.api.feature.FeatureSdkCore
import com.datadog.android.api.storage.DataWriter
import com.datadog.android.webview.internal.WebViewEventConsumer
import com.datadog.android.webview.internal.replay.WebViewReplayEventConsumer
import com.datadog.android.webview.internal.rum.domain.RumContext
import com.google.gson.JsonObject
import java.lang.IllegalStateException
Expand Down Expand Up @@ -41,7 +42,13 @@ internal class WebViewRumEventConsumer(
?.withWriteContext { datadogContext, eventBatchWriter ->
val rumContext = contextProvider.getRumContext(datadogContext)
if (rumContext != null && rumContext.sessionState == "TRACKED") {
val mappedEvent = map(event, datadogContext, rumContext)
val sessionReplayFeatureContext = datadogContext.featuresContext[
Feature.SESSION_REPLAY_FEATURE_NAME
]
val sessionReplayEnabled = sessionReplayFeatureContext?.get(
WebViewReplayEventConsumer.SESSION_REPLAY_ENABLED_KEY
) as? Boolean ?: false
val mappedEvent = map(event, datadogContext, rumContext, sessionReplayEnabled)
@Suppress("ThreadSafety") // inside worker thread context
dataWriter.write(eventBatchWriter, mappedEvent)
}
Expand All @@ -51,12 +58,13 @@ internal class WebViewRumEventConsumer(
private fun map(
event: JsonObject,
datadogContext: DatadogContext,
rumContext: RumContext?
rumContext: RumContext?,
sessionReplayEnabled: Boolean
): JsonObject {
try {
val timeOffset = event.get(VIEW_KEY_NAME)?.asJsonObject?.get(VIEW_ID_KEY_NAME)
?.asString?.let { offsetProvider.getOffset(it, datadogContext) } ?: 0L
return webViewRumEventMapper.mapEvent(event, rumContext, timeOffset)
return webViewRumEventMapper.mapEvent(event, rumContext, timeOffset, sessionReplayEnabled)
} catch (e: ClassCastException) {
sdkCore.internalLogger.log(
InternalLogger.Level.ERROR,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ internal class WebViewRumEventMapper(
fun mapEvent(
event: JsonObject,
rumContext: RumContext?,
timeOffset: Long
timeOffset: Long,
sessionReplayEnabled: Boolean
): JsonObject {
val containerObject = JsonObject().apply {
addProperty(SOURCE_KEY_NAME, SOURCE_VALUE)
Expand All @@ -42,18 +43,23 @@ internal class WebViewRumEventMapper(
val dd = event.get(DD_KEY_NAME)?.asJsonObject
if (dd != null) {
val ddSession = dd.get(DD_SESSION_KEY_NAME)?.asJsonObject ?: JsonObject()
// TODO RUM-3785 It was ViewEvent.Plan.PLAN_1 here before, but removed in order not to
// depend on RUM module. We may want to generate RUM models also in this package, but
// they shouldn't be public.
ddSession.addProperty(SESSION_PLAN_KEY_NAME, SESSION_PLAN_VALUE)
dd.add(DD_SESSION_KEY_NAME, ddSession)
if (!sessionReplayEnabled) {
// RUM-4084 disable webview SR if host app doesn't have SR
// dd.remove(DD_REPLAY_STATS)
}
}

if (rumContext != null) {
val application = event.getAsJsonObject(APPLICATION_KEY_NAME)?.asJsonObject
?: JsonObject()
val session = event.getAsJsonObject(SESSION_KEY_NAME)?.asJsonObject ?: JsonObject()
application.addProperty(ID_KEY_NAME, rumContext.applicationId)
session.addProperty(ID_KEY_NAME, rumContext.sessionId)
if (!sessionReplayEnabled) {
// RUM-4084 disable webview SR if host app doesn't have SR
session.remove(SESSION_HAS_REPLAY_NAME)
}
event.add(APPLICATION_KEY_NAME, application)
event.add(SESSION_KEY_NAME, session)
}
Expand All @@ -66,10 +72,10 @@ internal class WebViewRumEventMapper(
internal const val SESSION_KEY_NAME = "session"
internal const val DD_KEY_NAME = "_dd"
internal const val DD_SESSION_KEY_NAME = "session"
internal const val SESSION_PLAN_KEY_NAME = "plan"
internal const val DD_REPLAY_STATS = "replay_stats"
internal const val DATE_KEY_NAME = "date"
internal const val ID_KEY_NAME = "id"
internal const val SESSION_PLAN_VALUE = 1
internal const val SESSION_HAS_REPLAY_NAME = "has_replay"
internal const val VIEW_KEY_NAME = "view"
internal const val CONTAINER_KEY_NAME = "container"
internal const val SOURCE_KEY_NAME = "source"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,16 @@ internal class ViewEventForgeryFactory : ForgeryFactory<ViewEvent> {
)
},
dd = ViewEvent.Dd(
session = forge.aNullable { ViewEvent.DdSession(aNullable { getForgery() }) },
session = forge.aNullable { ViewEvent.DdSession(null, getForgery()) },
browserSdkVersion = forge.aNullable { aStringMatching("\\d+\\.\\d+\\.\\d+") },
documentVersion = forge.aPositiveLong(strict = true)
documentVersion = forge.aPositiveLong(strict = true),
replayStats = forge.aNullable {
ViewEvent.ReplayStats(
recordsCount = aLong(0),
segmentsCount = aLong(0),
segmentsTotalRawSize = aLong(0)
)
}
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ import com.datadog.android.utils.forge.Configurator
import com.datadog.android.utils.forge.aRumEventAsJson
import com.datadog.android.utils.verifyLog
import com.datadog.android.webview.internal.WebViewEventConsumer
import com.datadog.android.webview.internal.replay.WebViewReplayEventConsumer
import com.datadog.android.webview.internal.rum.domain.RumContext
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import fr.xgouchet.elmyr.Forge
import fr.xgouchet.elmyr.annotation.BoolForgery
import fr.xgouchet.elmyr.annotation.Forgery
import fr.xgouchet.elmyr.annotation.LongForgery
import fr.xgouchet.elmyr.junit5.ForgeConfiguration
Expand Down Expand Up @@ -106,6 +108,9 @@ internal class WebViewRumEventConsumerTest {
@Mock
lateinit var mockOffsetProvider: TimestampOffsetProvider

@BoolForgery
var fakeSessionReplayEnabled = false

@BeforeEach
fun `set up`(forge: Forge) {
fakeRumContext = fakeRumContext.copy(sessionState = "TRACKED")
Expand All @@ -117,10 +122,16 @@ internal class WebViewRumEventConsumerTest {
emptyMap()
}

val fakeFeaturesContext = mapOf(
Feature.SESSION_REPLAY_FEATURE_NAME to mapOf(
WebViewReplayEventConsumer.SESSION_REPLAY_ENABLED_KEY to fakeSessionReplayEnabled
)
)
fakeDatadogContext = fakeDatadogContext.copy(
time = fakeDatadogContext.time.copy(
serverTimeOffsetMs = fakeServerTimeOffsetInMillis
)
),
featuresContext = fakeFeaturesContext
)

whenever(
Expand Down Expand Up @@ -171,7 +182,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeViewEventAsJson,
fakeRumContext,
fakeServerTimeOffsetInMillis
fakeServerTimeOffsetInMillis,
fakeSessionReplayEnabled
)
).thenReturn(fakeMappedViewEvent)

Expand All @@ -196,7 +208,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeViewEventAsJson,
fakeRumContext,
fakeServerTimeOffsetInMillis
fakeServerTimeOffsetInMillis,
fakeSessionReplayEnabled
)
).thenReturn(fakeMappedViewEvent)

Expand All @@ -217,7 +230,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeViewEventAsJson,
null,
fakeServerTimeOffsetInMillis
fakeServerTimeOffsetInMillis,
fakeSessionReplayEnabled
)
).thenReturn(fakeMappedViewEvent)

Expand Down Expand Up @@ -245,7 +259,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeActionEventAsJson,
fakeRumContext,
fakeServerTimeOffsetInMillis
fakeServerTimeOffsetInMillis,
fakeSessionReplayEnabled
)
).thenReturn(fakeMappedActionEvent)

Expand All @@ -269,7 +284,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeActionEventAsJson,
fakeRumContext,
fakeServerTimeOffsetInMillis
fakeServerTimeOffsetInMillis,
fakeSessionReplayEnabled
)
).thenReturn(fakeMappedActionEvent)

Expand All @@ -290,7 +306,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeActionEventAsJson,
null,
fakeServerTimeOffsetInMillis
fakeServerTimeOffsetInMillis,
fakeSessionReplayEnabled
)
).thenReturn(fakeMappedActionEvent)

Expand Down Expand Up @@ -318,7 +335,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeResourceEventAsJson,
fakeRumContext,
fakeServerTimeOffsetInMillis
fakeServerTimeOffsetInMillis,
fakeSessionReplayEnabled
)
).thenReturn(fakeMappedResourceEvent)

Expand All @@ -342,7 +360,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeResourceEventAsJson,
fakeRumContext,
fakeServerTimeOffsetInMillis
fakeServerTimeOffsetInMillis,
fakeSessionReplayEnabled
)
).thenReturn(fakeMappedResourceEvent)

Expand All @@ -363,7 +382,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeResourceEventAsJson,
null,
fakeServerTimeOffsetInMillis
fakeServerTimeOffsetInMillis,
fakeSessionReplayEnabled
)
).thenReturn(fakeMappedResourceEvent)

Expand Down Expand Up @@ -391,7 +411,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeErrorEventAsJson,
fakeRumContext,
fakeServerTimeOffsetInMillis
fakeServerTimeOffsetInMillis,
fakeSessionReplayEnabled
)
).thenReturn(fakeMappedErrorEvent)

Expand All @@ -415,7 +436,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeErrorEventAsJson,
fakeRumContext,
fakeServerTimeOffsetInMillis
fakeServerTimeOffsetInMillis,
fakeSessionReplayEnabled
)
).thenReturn(fakeMappedErrorEvent)

Expand All @@ -436,7 +458,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeErrorEventAsJson,
null,
fakeServerTimeOffsetInMillis
fakeServerTimeOffsetInMillis,
fakeSessionReplayEnabled
)
).thenReturn(fakeMappedErrorEvent)

Expand Down Expand Up @@ -464,7 +487,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeLongTaskEventAsJson,
fakeRumContext,
fakeServerTimeOffsetInMillis
fakeServerTimeOffsetInMillis,
fakeSessionReplayEnabled
)
).thenReturn(fakeMappedLongTaskEvent)

Expand All @@ -488,7 +512,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeLongTaskEventAsJson,
fakeRumContext,
fakeServerTimeOffsetInMillis
fakeServerTimeOffsetInMillis,
fakeSessionReplayEnabled
)
)
.thenReturn(fakeMappedLongTaskEvent)
Expand All @@ -510,7 +535,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeLongTaskEventAsJson,
null,
fakeServerTimeOffsetInMillis
fakeServerTimeOffsetInMillis,
fakeSessionReplayEnabled
)
).thenReturn(fakeMappedLongTaskEvent)

Expand All @@ -537,7 +563,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeRumEvent,
fakeRumContext,
fakeServerTimeOffsetInMillis
fakeServerTimeOffsetInMillis,
fakeSessionReplayEnabled
)
).thenThrow(fakeException)

Expand All @@ -557,7 +584,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeRumEvent,
fakeRumContext,
fakeServerTimeOffsetInMillis
fakeServerTimeOffsetInMillis,
fakeSessionReplayEnabled
)
).thenThrow(fakeException)

Expand All @@ -583,7 +611,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeRumEvent,
fakeRumContext,
0
0,
fakeSessionReplayEnabled
)
).thenReturn(fakeMappedRumEvent)

Expand All @@ -605,7 +634,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeRumEvent,
fakeRumContext,
0
0,
fakeSessionReplayEnabled
)
).thenReturn(fakeMappedRumEvent)

Expand All @@ -627,7 +657,8 @@ internal class WebViewRumEventConsumerTest {
mockWebViewRumEventMapper.mapEvent(
fakeRumEvent,
fakeRumContext,
0
0,
fakeSessionReplayEnabled
)
).thenReturn(fakeMappedRumEvent)

Expand Down
Loading

0 comments on commit f9f810a

Please sign in to comment.