Skip to content

Commit 82680fb

Browse files
committed
Merge branch 'rz/feat/session-replay-breadcrumbs' into rz/feat/session-replay-public-api
2 parents 9686a74 + 51cc432 commit 82680fb

File tree

5 files changed

+126
-17
lines changed

5 files changed

+126
-17
lines changed

sentry-android-replay/src/main/java/io/sentry/android/replay/capture/BaseCaptureStrategy.kt

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -171,25 +171,73 @@ internal abstract class BaseCaptureStrategy(
171171

172172
hub?.configureScope { scope ->
173173
scope.breadcrumbs.forEach { breadcrumb ->
174-
if (breadcrumb.timestamp.after(segmentTimestamp) && breadcrumb.timestamp.before(endTimestamp)) {
175-
recordingPayload += RRWebBreadcrumbEvent().apply {
176-
timestamp = breadcrumb.timestamp.time
177-
breadcrumbTimestamp = breadcrumb.timestamp.time
178-
breadcrumbType = breadcrumb.type
179-
category = breadcrumb.category
180-
message = breadcrumb.message
181-
data = breadcrumb.data
174+
if (breadcrumb.timestamp.after(segmentTimestamp) &&
175+
breadcrumb.timestamp.before(endTimestamp)) {
176+
// TODO: rework this later when aligned with iOS and frontend
177+
var breadcrumbMessage: String? = null
178+
val breadcrumbCategory: String?
179+
val breadcrumbData = mutableMapOf<String, Any?>()
180+
when {
181+
breadcrumb.category == "http" -> return@forEach
182+
183+
breadcrumb.category == "device.orientation" -> {
184+
breadcrumbCategory = breadcrumb.category!!
185+
breadcrumbMessage = breadcrumb.data["position"] as? String ?: ""
186+
}
187+
188+
breadcrumb.type == "navigation" -> {
189+
breadcrumbCategory = "navigation"
190+
breadcrumbData["to"] = when {
191+
breadcrumb.data["state"] == "resumed" -> breadcrumb.data["screen"] as? String
192+
breadcrumb.category == "app.lifecycle" -> breadcrumb.data["state"] as? String
193+
"to" in breadcrumb.data -> breadcrumb.data["to"] as? String
194+
else -> return@forEach
195+
} ?: return@forEach
196+
}
197+
198+
breadcrumb.category in setOf("ui.click", "ui.scroll", "ui.swipe") -> {
199+
breadcrumbCategory = breadcrumb.category!!
200+
breadcrumbMessage = (
201+
breadcrumb.data["view.id"]
202+
?: breadcrumb.data["view.class"]
203+
?: breadcrumb.data["view.tag"]
204+
) as? String ?: ""
205+
}
206+
207+
breadcrumb.type == "system" -> {
208+
breadcrumbCategory = breadcrumb.type!!
209+
breadcrumbMessage = breadcrumb.data.entries.joinToString() as? String ?: ""
210+
}
211+
212+
else -> {
213+
breadcrumbCategory = breadcrumb.category
214+
breadcrumbMessage = breadcrumb.message
215+
}
216+
}
217+
if (!breadcrumbCategory.isNullOrEmpty()) {
218+
recordingPayload += RRWebBreadcrumbEvent().apply {
219+
timestamp = breadcrumb.timestamp.time
220+
breadcrumbTimestamp = breadcrumb.timestamp.time / 1000.0
221+
breadcrumbType = "default"
222+
category = breadcrumbCategory
223+
message = breadcrumbMessage
224+
data = breadcrumbData
225+
}
182226
}
183227
}
184228
}
185229
}
186230

187231
val recording = ReplayRecording().apply {
188232
this.segmentId = segmentId
189-
payload = recordingPayload
233+
payload = recordingPayload.sortedBy { it.timestamp }
190234
}
191235

192-
return ReplaySegment.Created(videoDuration = duration, replay = replay, recording = recording)
236+
return ReplaySegment.Created(
237+
videoDuration = duration,
238+
replay = replay,
239+
recording = recording
240+
)
193241
}
194242

195243
override fun onConfigurationChanged(recorderConfig: ScreenshotRecorderConfig) {

sentry/api/sentry.api

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5040,7 +5040,7 @@ public final class io/sentry/protocol/ViewHierarchyNode$JsonKeys {
50405040
public final class io/sentry/rrweb/RRWebBreadcrumbEvent : io/sentry/rrweb/RRWebEvent, io/sentry/JsonSerializable, io/sentry/JsonUnknown {
50415041
public static final field EVENT_TAG Ljava/lang/String;
50425042
public fun <init> ()V
5043-
public fun getBreadcrumbTimestamp ()J
5043+
public fun getBreadcrumbTimestamp ()D
50445044
public fun getBreadcrumbType ()Ljava/lang/String;
50455045
public fun getCategory ()Ljava/lang/String;
50465046
public fun getData ()Ljava/util/Map;
@@ -5050,7 +5050,7 @@ public final class io/sentry/rrweb/RRWebBreadcrumbEvent : io/sentry/rrweb/RRWebE
50505050
public fun getTag ()Ljava/lang/String;
50515051
public fun getUnknown ()Ljava/util/Map;
50525052
public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V
5053-
public fun setBreadcrumbTimestamp (J)V
5053+
public fun setBreadcrumbTimestamp (D)V
50545054
public fun setBreadcrumbType (Ljava/lang/String;)V
50555055
public fun setCategory (Ljava/lang/String;)V
50565056
public fun setData (Ljava/util/Map;)V

sentry/src/main/java/io/sentry/rrweb/RRWebBreadcrumbEvent.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.sentry.util.CollectionUtils;
1010
import io.sentry.vendor.gson.stream.JsonToken;
1111
import java.io.IOException;
12+
import java.math.BigDecimal;
1213
import java.util.HashMap;
1314
import java.util.Map;
1415
import java.util.concurrent.ConcurrentHashMap;
@@ -20,7 +21,7 @@ public final class RRWebBreadcrumbEvent extends RRWebEvent
2021
public static final String EVENT_TAG = "breadcrumb";
2122

2223
private @NotNull String tag;
23-
private long breadcrumbTimestamp;
24+
private double breadcrumbTimestamp;
2425
private @Nullable String breadcrumbType;
2526
private @Nullable String category;
2627
private @Nullable String message;
@@ -45,11 +46,11 @@ public void setTag(final @NotNull String tag) {
4546
this.tag = tag;
4647
}
4748

48-
public long getBreadcrumbTimestamp() {
49+
public double getBreadcrumbTimestamp() {
4950
return breadcrumbTimestamp;
5051
}
5152

52-
public void setBreadcrumbTimestamp(final long breadcrumbTimestamp) {
53+
public void setBreadcrumbTimestamp(final double breadcrumbTimestamp) {
5354
this.breadcrumbTimestamp = breadcrumbTimestamp;
5455
}
5556

@@ -165,7 +166,7 @@ private void serializePayload(final @NotNull ObjectWriter writer, final @NotNull
165166
if (breadcrumbType != null) {
166167
writer.name(JsonKeys.TYPE).value(breadcrumbType);
167168
}
168-
writer.name(JsonKeys.TIMESTAMP).value(breadcrumbTimestamp);
169+
writer.name(JsonKeys.TIMESTAMP).value(logger, BigDecimal.valueOf(breadcrumbTimestamp));
169170
if (category != null) {
170171
writer.name(JsonKeys.CATEGORY).value(category);
171172
}
@@ -263,7 +264,7 @@ private void deserializePayload(
263264
event.breadcrumbType = reader.nextStringOrNull();
264265
break;
265266
case JsonKeys.TIMESTAMP:
266-
event.breadcrumbTimestamp = reader.nextLong();
267+
event.breadcrumbTimestamp = reader.nextDouble();
267268
break;
268269
case JsonKeys.CATEGORY:
269270
event.category = reader.nextStringOrNull();
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package io.sentry.rrweb
2+
3+
import io.sentry.ILogger
4+
import io.sentry.protocol.SerializationUtils
5+
import org.junit.Test
6+
import org.mockito.kotlin.mock
7+
import kotlin.test.assertEquals
8+
9+
class RRWebBreadcrumbEventSerializationTest {
10+
class Fixture {
11+
val logger = mock<ILogger>()
12+
13+
fun getSut() = RRWebBreadcrumbEvent().apply {
14+
timestamp = 12345678901
15+
breadcrumbType = "default"
16+
breadcrumbTimestamp = 12345678.901
17+
category = "navigation"
18+
message = "message"
19+
data = mapOf(
20+
"screen" to "MainActivity",
21+
"state" to "resumed"
22+
)
23+
}
24+
}
25+
26+
private val fixture = Fixture()
27+
28+
@Test
29+
fun serialize() {
30+
val expected = SerializationUtils.sanitizedFile("json/rrweb_breadcrumb_event.json")
31+
val actual = SerializationUtils.serializeToString(fixture.getSut(), fixture.logger)
32+
assertEquals(expected, actual)
33+
}
34+
35+
@Test
36+
fun deserialize() {
37+
val expectedJson = SerializationUtils.sanitizedFile("json/rrweb_breadcrumb_event.json")
38+
val actual =
39+
SerializationUtils.deserializeJson(expectedJson, RRWebBreadcrumbEvent.Deserializer(), fixture.logger)
40+
val actualJson = SerializationUtils.serializeToString(actual, fixture.logger)
41+
assertEquals(expectedJson, actualJson)
42+
}
43+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"type": 5,
3+
"timestamp": 12345678901,
4+
"data": {
5+
"tag": "breadcrumb",
6+
"payload": {
7+
"type": "default",
8+
"timestamp": 12345678.901,
9+
"category": "navigation",
10+
"message": "message",
11+
"data": {
12+
"screen": "MainActivity",
13+
"state": "resumed"
14+
}
15+
}
16+
}
17+
}

0 commit comments

Comments
 (0)