Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
### Fixes

- `SentryOptions.setTracePropagationTargets` is no longer marked internal ([#4170](https://github.com/getsentry/sentry-java/pull/4170))
- Session Replay: Fix crash when a navigation breadcrumb does not have "to" destination ([#4185](https://github.com/getsentry/sentry-java/pull/4185))
- Session Replay: Cap video segment duration to maximum 5 minutes to prevent endless video encoding in background ([#4185](https://github.com/getsentry/sentry-java/pull/4185))
- Check `tracePropagationTargets` in OpenTelemetry propagator ([#4191](https://github.com/getsentry/sentry-java/pull/4191))
- If a URL can be retrieved from OpenTelemetry span attributes, we check it against `tracePropagationTargets` before attaching `sentry-trace` and `baggage` headers to outgoing requests
- If no URL can be retrieved we always attach the headers
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ internal interface CaptureStrategy {
companion object {
private const val BREADCRUMB_START_OFFSET = 100L

// 5 minutes, otherwise relay will just drop it. Can prevent the case where the device
// time is wrong and the segment is too long.
private const val MAX_SEGMENT_DURATION = 1000L * 60 * 5

fun createSegment(
scopes: IScopes?,
options: SentryOptions,
Expand All @@ -76,7 +80,7 @@ internal interface CaptureStrategy {
events: Deque<RRWebEvent>
): ReplaySegment {
val generatedVideo = cache?.createVideoOf(
duration,
minOf(duration, MAX_SEGMENT_DURATION),
currentSegmentTimestamp.time,
segmentId,
height,
Expand Down Expand Up @@ -179,7 +183,9 @@ internal interface CaptureStrategy {
recordingPayload += rrwebEvent

// fill in the urls array from navigation breadcrumbs
if ((rrwebEvent as? RRWebBreadcrumbEvent)?.category == "navigation") {
if ((rrwebEvent as? RRWebBreadcrumbEvent)?.category == "navigation" &&
rrwebEvent.data?.getOrElse("to", { null }) is String
) {
urls.add(rrwebEvent.data!!["to"] as String)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,30 @@ class SessionCaptureStrategyTest {
)
}

@Test
fun `does not throw when navigation destination is not a String`() {
val now =
System.currentTimeMillis() + (fixture.options.sessionReplay.sessionSegmentDuration * 5)
val strategy = fixture.getSut(dateProvider = { now })
strategy.start(fixture.recorderConfig)

fixture.scope.addBreadcrumb(Breadcrumb().apply { category = "navigation" })

strategy.onScreenshotRecorded(mock<Bitmap>()) {}

verify(fixture.scopes).captureReplay(
check {
assertNull(it.urls?.firstOrNull())
},
check {
val breadcrumbEvents =
it.replayRecording?.payload?.filterIsInstance<RRWebBreadcrumbEvent>()
assertEquals("navigation", breadcrumbEvents?.first()?.category)
assertNull(breadcrumbEvents?.first()?.data?.get("to"))
}
)
}

@Test
fun `sets screen from scope as replay url`() {
fixture.scope.screen = "MainActivity"
Expand Down
Loading