Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
- Fix SDK callback error handling ([#6140](https://github.com/getsentry/sentry-java/pull/6140))
- Add `DiscardReason.CALLBACK_ERROR` and use it for telemetry dropped when a `beforeSend*` callback throws. `OnDiscardCallback` can now receive this value.
- Drop telemetry and record `callback_error` when a customer event processor throws instead of continuing with a potentially partially processed item. SDK-owned processor failures are logged and processing continues without a `callback_error` client report.
- Drop breadcrumbs when `beforeBreadcrumb` throws instead of storing exception details on the breadcrumb.
- Disable URL caching when reading `META-INF/MANIFEST.MF` files during version detection so that the SDK no longer keeps jar file handles open for the life of the process ([#6124](https://github.com/getsentry/sentry-java/pull/6124)
- Keep the `EventListener` wrapped by `SentryOkHttpEventListener` per `Call` ([#6003](https://github.com/getsentry/sentry-java/pull/6003))

Expand Down
7 changes: 2 additions & 5 deletions sentry/src/main/java/io/sentry/Scope.java
Original file line number Diff line number Diff line change
Expand Up @@ -472,12 +472,9 @@ public Queue<Breadcrumb> getBreadcrumbs() {
.getLogger()
.log(
SentryLevel.ERROR,
"The BeforeBreadcrumbCallback callback threw an exception. Exception details will be added to the breadcrumb.",
"The BeforeBreadcrumb callback threw an exception. Dropping breadcrumb.",
e);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was an internal discussion around reporting dropped breadcrumbs in client reports via log_item category. This creates confusion since you can't tell whether a log item or breadcrumb was dropped. Instead we've decided not to report dropped breadcrumbs.


if (e.getMessage() != null) {
breadcrumb.setData("sentry:message", e.getMessage());
}
return null;
}
return breadcrumb;
}
Expand Down
42 changes: 36 additions & 6 deletions sentry/src/test/java/io/sentry/ScopeTest.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package io.sentry

import com.google.common.truth.Truth.assertThat
import io.sentry.SentryLevel.WARNING
import io.sentry.clientreport.ClientReportTestHelper.Companion.assertClientReport
import io.sentry.protocol.Request
import io.sentry.protocol.SentryId
import io.sentry.protocol.User
Expand Down Expand Up @@ -334,16 +336,44 @@ class ScopeTest {
}

@Test
fun `when adding breadcrumb, executeBreadcrumb will be executed and throw, but breadcrumb will be added`() {
val exception = Exception("test")
fun `when beforeBreadcrumb throws, breadcrumb is dropped without notifying observers`() {
val observer = mock<IScopeObserver>()
val options =
SentryOptions().apply {
setBeforeBreadcrumb { _, _ -> throw Exception("test") }
addScopeObserver(observer)
}

val options = SentryOptions().apply { setBeforeBreadcrumb { _, _ -> throw exception } }
val scope = Scope(options)
val breadcrumb = Breadcrumb()
scope.addBreadcrumb(breadcrumb)

assertThat(scope.breadcrumbs).isEmpty()
assertThat(breadcrumb.data).doesNotContainKey("sentry:message")
verifyNoInteractions(observer)
assertClientReport(options.clientReportRecorder, emptyList())
}

@Test
fun `when beforeBreadcrumb throws, later breadcrumbs can still be added`() {
var invocationCount = 0
val options =
SentryOptions().apply {
setBeforeBreadcrumb { breadcrumb, _ ->
invocationCount++
if (invocationCount == 1) {
throw Exception("test")
}
breadcrumb
}
}

val scope = Scope(options)
val actual = Breadcrumb()
scope.addBreadcrumb(actual)
scope.addBreadcrumb(Breadcrumb("dropped"))
scope.addBreadcrumb(Breadcrumb("kept"))

assertEquals("test", actual.data["sentry:message"])
assertThat(invocationCount).isEqualTo(2)
assertThat(scope.breadcrumbs.single().message).isEqualTo("kept")
}

@Test
Expand Down
16 changes: 9 additions & 7 deletions sentry/src/test/java/io/sentry/ScopesTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.sentry

import com.google.common.truth.Truth.assertThat
import io.sentry.backpressure.IBackpressureMonitor
import io.sentry.cache.EnvelopeCache
import io.sentry.clientreport.ClientReportTestHelper.Companion.assertClientReport
Expand Down Expand Up @@ -236,22 +237,23 @@ class ScopesTest {
}

@Test
fun `when beforeSend throws an exception, breadcrumb adds an entry to the data field with exception message`() {
val exception = Exception("test")

fun `when beforeBreadcrumb throws an exception, breadcrumb is dropped`() {
val options = SentryOptions()
options.cacheDirPath = file.absolutePath
options.beforeBreadcrumb = SentryOptions.BeforeBreadcrumbCallback { _: Breadcrumb, _: Any? ->
throw exception
throw Exception("test")
}
options.dsn = "https://key@sentry.io/proj"
options.setSerializer(mock())
val sut = createScopes(options)

val actual = Breadcrumb()
sut.addBreadcrumb(actual)
val breadcrumb = Breadcrumb()
sut.addBreadcrumb(breadcrumb)

assertEquals("test", actual.data["sentry:message"])
var breadcrumbs: Queue<Breadcrumb>? = null
sut.configureScope { breadcrumbs = it.breadcrumbs }
assertThat(breadcrumbs).isEmpty()
assertThat(breadcrumb.data).doesNotContainKey("sentry:message")
}

@Test
Expand Down
Loading