Skip to content

Commit 8011314

Browse files
authored
Merge 82b9faf into 22bba29
2 parents 22bba29 + 82b9faf commit 8011314

File tree

11 files changed

+181
-11
lines changed

11 files changed

+181
-11
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@
44

55
### Summary
66

7+
### Features
8+
9+
- Add `options.ignoreExceptions` to filter out exceptions that match a certain String or Regex ([#4083](https://github.com/getsentry/sentry-java/pull/4083))
10+
- Can be set in `sentry.properties`, e.g. `ignored-exceptions=java.lang.RuntimeException,io.sentry..*`
11+
- Can be set in environment variables, e.g. `SENTRY_IGNORED_EXCEPTIONS=java.lang.RuntimeException,io.sentry..*`
12+
- For Spring Boot, it can be set in `application.properties`, e.g. `sentry.ignored-exceptions=java.lang.RuntimeException,io.sentry..*`
13+
14+
## 8.0.0
15+
16+
### Summary
17+
718
Version 8 of the Sentry Android/Java SDK brings a variety of features and fixes. The most notable changes are:
819

920
- `Hub` has been replaced by `Scopes`

sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ class SentryAutoConfigurationTest {
174174
"sentry.enabled=false",
175175
"sentry.send-modules=false",
176176
"sentry.ignored-checkins=slug1,slugB",
177+
"sentry.ignored-exceptions=com.some.Exception,io.sentry..*",
177178
"sentry.ignored-transactions=transactionName1,transactionNameB",
178179
"sentry.enable-backpressure-handling=false",
179180
"sentry.enable-spotlight=true",
@@ -215,6 +216,7 @@ class SentryAutoConfigurationTest {
215216
assertThat(options.isEnabled).isEqualTo(false)
216217
assertThat(options.isSendModules).isEqualTo(false)
217218
assertThat(options.ignoredCheckIns).containsOnly(FilterString("slug1"), FilterString("slugB"))
219+
assertThat(options.ignoredExceptions).containsOnly(FilterString("com.some.Exception"), FilterString("io.sentry..*"))
218220
assertThat(options.ignoredTransactions).containsOnly(FilterString("transactionName1"), FilterString("transactionNameB"))
219221
assertThat(options.isEnableBackpressureHandling).isEqualTo(false)
220222
assertThat(options.isForceInit).isEqualTo(true)

sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ class SentryAutoConfigurationTest {
173173
"sentry.enabled=false",
174174
"sentry.send-modules=false",
175175
"sentry.ignored-checkins=slug1,slugB",
176+
"sentry.ignored-exceptions=com.some.Exception,io.sentry..*",
176177
"sentry.ignored-transactions=transactionName1,transactionNameB",
177178
"sentry.enable-backpressure-handling=false",
178179
"sentry.enable-spotlight=true",
@@ -214,6 +215,7 @@ class SentryAutoConfigurationTest {
214215
assertThat(options.isEnabled).isEqualTo(false)
215216
assertThat(options.isSendModules).isEqualTo(false)
216217
assertThat(options.ignoredCheckIns).containsOnly(FilterString("slug1"), FilterString("slugB"))
218+
assertThat(options.ignoredExceptions).containsOnly(FilterString("com.some.Exception"), FilterString("io.sentry..*"))
217219
assertThat(options.ignoredTransactions).containsOnly(FilterString("transactionName1"), FilterString("transactionNameB"))
218220
assertThat(options.isEnableBackpressureHandling).isEqualTo(false)
219221
assertThat(options.isForceInit).isEqualTo(true)

sentry/api/sentry.api

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ public final class io/sentry/ExternalOptions {
436436
public fun <init> ()V
437437
public fun addBundleId (Ljava/lang/String;)V
438438
public fun addContextTag (Ljava/lang/String;)V
439+
public fun addIgnoredException (Ljava/lang/String;)V
439440
public fun addIgnoredExceptionForType (Ljava/lang/Class;)V
440441
public fun addInAppExclude (Ljava/lang/String;)V
441442
public fun addInAppInclude (Ljava/lang/String;)V
@@ -452,6 +453,7 @@ public final class io/sentry/ExternalOptions {
452453
public fun getEnvironment ()Ljava/lang/String;
453454
public fun getIdleTimeout ()Ljava/lang/Long;
454455
public fun getIgnoredCheckIns ()Ljava/util/List;
456+
public fun getIgnoredExceptions ()Ljava/util/List;
455457
public fun getIgnoredExceptionsForType ()Ljava/util/Set;
456458
public fun getIgnoredTransactions ()Ljava/util/List;
457459
public fun getInAppExcludes ()Ljava/util/List;
@@ -491,6 +493,7 @@ public final class io/sentry/ExternalOptions {
491493
public fun setGlobalHubMode (Ljava/lang/Boolean;)V
492494
public fun setIdleTimeout (Ljava/lang/Long;)V
493495
public fun setIgnoredCheckIns (Ljava/util/List;)V
496+
public fun setIgnoredExceptions (Ljava/util/List;)V
494497
public fun setIgnoredTransactions (Ljava/util/List;)V
495498
public fun setMaxRequestBodySize (Lio/sentry/SentryOptions$RequestSize;)V
496499
public fun setPrintUncaughtStackTrace (Ljava/lang/Boolean;)V
@@ -2814,6 +2817,7 @@ public class io/sentry/SentryOptions {
28142817
public fun addContextTag (Ljava/lang/String;)V
28152818
public fun addEventProcessor (Lio/sentry/EventProcessor;)V
28162819
public fun addIgnoredCheckIn (Ljava/lang/String;)V
2820+
public fun addIgnoredException (Ljava/lang/String;)V
28172821
public fun addIgnoredExceptionForType (Ljava/lang/Class;)V
28182822
public fun addIgnoredSpanOrigin (Ljava/lang/String;)V
28192823
public fun addIgnoredTransaction (Ljava/lang/String;)V
@@ -2855,6 +2859,7 @@ public class io/sentry/SentryOptions {
28552859
public fun getGestureTargetLocators ()Ljava/util/List;
28562860
public fun getIdleTimeout ()Ljava/lang/Long;
28572861
public fun getIgnoredCheckIns ()Ljava/util/List;
2862+
public fun getIgnoredExceptions ()Ljava/util/List;
28582863
public fun getIgnoredExceptionsForType ()Ljava/util/Set;
28592864
public fun getIgnoredSpanOrigins ()Ljava/util/List;
28602865
public fun getIgnoredTransactions ()Ljava/util/List;
@@ -2987,6 +2992,7 @@ public class io/sentry/SentryOptions {
29872992
public fun setGlobalHubMode (Ljava/lang/Boolean;)V
29882993
public fun setIdleTimeout (Ljava/lang/Long;)V
29892994
public fun setIgnoredCheckIns (Ljava/util/List;)V
2995+
public fun setIgnoredExceptions (Ljava/util/List;)V
29902996
public fun setIgnoredSpanOrigins (Ljava/util/List;)V
29912997
public fun setIgnoredTransactions (Ljava/util/List;)V
29922998
public fun setInitPriority (Lio/sentry/InitPriority;)V
@@ -6055,6 +6061,7 @@ public final class io/sentry/util/EventProcessorUtils {
60556061
public final class io/sentry/util/ExceptionUtils {
60566062
public fun <init> ()V
60576063
public static fun findRootCause (Ljava/lang/Throwable;)Ljava/lang/Throwable;
6064+
public static fun isIgnored (Ljava/util/Set;Ljava/util/List;Ljava/lang/Throwable;)Z
60586065
}
60596066

60606067
public final class io/sentry/util/FileUtils {

sentry/src/main/java/io/sentry/ExternalOptions.java

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package io.sentry;
22

33
import io.sentry.config.PropertiesProvider;
4-
import java.util.List;
5-
import java.util.Locale;
6-
import java.util.Map;
7-
import java.util.Set;
4+
import java.util.*;
85
import java.util.concurrent.ConcurrentHashMap;
96
import java.util.concurrent.CopyOnWriteArrayList;
107
import java.util.concurrent.CopyOnWriteArraySet;
@@ -39,6 +36,7 @@ public final class ExternalOptions {
3936
private @Nullable Long idleTimeout;
4037
private final @NotNull Set<Class<? extends Throwable>> ignoredExceptionsForType =
4138
new CopyOnWriteArraySet<>();
39+
private @Nullable List<String> ignoredExceptions;
4240
private @Nullable Boolean printUncaughtStackTrace;
4341
private @Nullable Boolean sendClientReports;
4442
private @NotNull Set<String> bundleIds = new CopyOnWriteArraySet<>();
@@ -130,6 +128,8 @@ public final class ExternalOptions {
130128
}
131129
options.setIdleTimeout(propertiesProvider.getLongProperty("idle-timeout"));
132130

131+
options.setIgnoredExceptions(propertiesProvider.getList("ignored-exceptions"));
132+
133133
options.setEnabled(propertiesProvider.getBooleanProperty("enabled"));
134134

135135
options.setEnablePrettySerializationOutput(
@@ -373,6 +373,21 @@ public void setIdleTimeout(final @Nullable Long idleTimeout) {
373373
this.idleTimeout = idleTimeout;
374374
}
375375

376+
public @Nullable List<String> getIgnoredExceptions() {
377+
return ignoredExceptions;
378+
}
379+
380+
public void setIgnoredExceptions(final @Nullable List<String> ignoredExceptions) {
381+
this.ignoredExceptions = ignoredExceptions;
382+
}
383+
384+
public void addIgnoredException(final @NotNull String pattern) {
385+
if (ignoredExceptions == null) {
386+
ignoredExceptions = new ArrayList<>();
387+
}
388+
ignoredExceptions.add(pattern);
389+
}
390+
376391
public @Nullable Boolean getSendClientReports() {
377392
return sendClientReports;
378393
}

sentry/src/main/java/io/sentry/SentryClient.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,7 @@
1111
import io.sentry.protocol.SentryTransaction;
1212
import io.sentry.transport.ITransport;
1313
import io.sentry.transport.RateLimiter;
14-
import io.sentry.util.CheckInUtils;
15-
import io.sentry.util.HintUtils;
16-
import io.sentry.util.Objects;
17-
import io.sentry.util.Random;
18-
import io.sentry.util.SentryRandom;
19-
import io.sentry.util.TracingUtils;
14+
import io.sentry.util.*;
2015
import java.io.Closeable;
2116
import java.io.IOException;
2217
import java.util.ArrayList;
@@ -103,7 +98,11 @@ private boolean shouldApplyScopeData(final @NotNull CheckIn event, final @NotNul
10398

10499
if (event != null) {
105100
final Throwable eventThrowable = event.getThrowable();
106-
if (eventThrowable != null && options.containsIgnoredExceptionForType(eventThrowable)) {
101+
if (eventThrowable != null
102+
&& ExceptionUtils.isIgnored(
103+
options.getIgnoredExceptionsForType(),
104+
options.getIgnoredExceptions(),
105+
eventThrowable)) {
107106
options
108107
.getLogger()
109108
.log(

sentry/src/main/java/io/sentry/SentryOptions.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ public class SentryOptions {
6969
private final @NotNull Set<Class<? extends Throwable>> ignoredExceptionsForType =
7070
new CopyOnWriteArraySet<>();
7171

72+
/**
73+
* Exception names or regex patterns that the captured exception will be tested against. If there
74+
* is a match, the captured exception will not be sent to Sentry as {@link SentryEvent}.
75+
*/
76+
private @Nullable List<FilterString> ignoredExceptions = null;
77+
7278
/**
7379
* Code that provides middlewares, bindings or hooks into certain frameworks or environments,
7480
* along with code that inserts those bindings and activates them.
@@ -1572,6 +1578,32 @@ boolean containsIgnoredExceptionForType(final @NotNull Throwable throwable) {
15721578
return this.ignoredExceptionsForType.contains(throwable.getClass());
15731579
}
15741580

1581+
public @Nullable List<FilterString> getIgnoredExceptions() {
1582+
return ignoredExceptions;
1583+
}
1584+
1585+
public void setIgnoredExceptions(final @Nullable List<String> ignoredExceptions) {
1586+
if (ignoredExceptions == null) {
1587+
this.ignoredExceptions = null;
1588+
} else {
1589+
@NotNull final List<FilterString> patterns = new ArrayList<>();
1590+
for (String pattern : ignoredExceptions) {
1591+
if (pattern != null && !pattern.isEmpty()) {
1592+
patterns.add(new FilterString(pattern));
1593+
}
1594+
}
1595+
1596+
this.ignoredExceptions = patterns;
1597+
}
1598+
}
1599+
1600+
public void addIgnoredException(final @NotNull String pattern) {
1601+
if (ignoredExceptions == null) {
1602+
ignoredExceptions = new ArrayList<>();
1603+
}
1604+
ignoredExceptions.add(new FilterString(pattern));
1605+
}
1606+
15751607
/**
15761608
* Returns the maximum number of spans that can be attached to single transaction.
15771609
*
@@ -2801,6 +2833,10 @@ public void merge(final @NotNull ExternalOptions options) {
28012833
final List<String> ignoredTransactions = new ArrayList<>(options.getIgnoredTransactions());
28022834
setIgnoredTransactions(ignoredTransactions);
28032835
}
2836+
if (options.getIgnoredExceptions() != null) {
2837+
final List<String> ignoredExceptions = new ArrayList<>(options.getIgnoredExceptions());
2838+
setIgnoredExceptions(ignoredExceptions);
2839+
}
28042840
if (options.isEnableBackpressureHandling() != null) {
28052841
setEnableBackpressureHandling(options.isEnableBackpressureHandling());
28062842
}

sentry/src/main/java/io/sentry/util/ExceptionUtils.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package io.sentry.util;
22

3+
import io.sentry.FilterString;
4+
import java.util.List;
5+
import java.util.Set;
36
import org.jetbrains.annotations.ApiStatus;
47
import org.jetbrains.annotations.NotNull;
8+
import org.jetbrains.annotations.Nullable;
59

610
@ApiStatus.Internal
711
public final class ExceptionUtils {
@@ -20,4 +24,42 @@ public final class ExceptionUtils {
2024
}
2125
return rootCause;
2226
}
27+
28+
/** Checks if an exception has been ignored. */
29+
@ApiStatus.Internal
30+
public static @NotNull boolean isIgnored(
31+
final @NotNull Set<Class<? extends Throwable>> ignoredExceptionsForType,
32+
final @Nullable List<FilterString> ignoredExceptions,
33+
final @NotNull Throwable throwable) {
34+
if (throwable == null) {
35+
return false;
36+
}
37+
38+
final Class<? extends Throwable> throwableClass = throwable.getClass();
39+
if (ignoredExceptionsForType.contains(throwableClass)) {
40+
return true;
41+
}
42+
43+
if (ignoredExceptions == null || ignoredExceptions.isEmpty()) {
44+
return false;
45+
}
46+
final String throwableClassName = throwableClass.getCanonicalName();
47+
if (throwableClassName == null) {
48+
return false;
49+
}
50+
51+
for (final FilterString filter : ignoredExceptions) {
52+
if (filter.getFilterString().equals(throwableClassName)) {
53+
return true;
54+
}
55+
}
56+
57+
for (final FilterString filter : ignoredExceptions) {
58+
if (filter.matches(throwableClassName)) {
59+
return true;
60+
}
61+
}
62+
63+
return false;
64+
}
2365
}

sentry/src/test/java/io/sentry/ExternalOptionsTest.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,16 @@ class ExternalOptionsTest {
209209
}
210210
}
211211

212+
@Test
213+
fun `creates options with ignored exception patterns using external properties`() {
214+
val logger = mock<ILogger>()
215+
withPropertiesFile("ignored-exceptions=java.lang.RuntimeException,io.sentry..*", logger) { options ->
216+
System.out.println(options.ignoredExceptions)
217+
assertTrue(options.ignoredExceptions!!.contains("java.lang.RuntimeException"))
218+
assertTrue(options.ignoredExceptions!!.contains("io.sentry..*"))
219+
}
220+
}
221+
212222
@Test
213223
fun `creates options with single bundle ID using external properties`() {
214224
withPropertiesFile("bundle-ids=12ea7a02-46ac-44c0-a5bb-6d1fd9586411") { options ->

sentry/src/test/java/io/sentry/SentryClientTest.kt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import org.junit.rules.TemporaryFolder
3232
import org.mockito.kotlin.any
3333
import org.mockito.kotlin.anyOrNull
3434
import org.mockito.kotlin.argumentCaptor
35+
import org.mockito.kotlin.atLeast
3536
import org.mockito.kotlin.check
3637
import org.mockito.kotlin.doAnswer
3738
import org.mockito.kotlin.eq
@@ -1758,6 +1759,49 @@ class SentryClientTest {
17581759
verify(fixture.transport, never()).send(any(), anyOrNull())
17591760
}
17601761

1762+
@Test
1763+
fun `when exception matches pattern in ignoredExceptions, capturing event does not send it`() {
1764+
fixture.sentryOptions.addIgnoredException(IllegalStateException::class.java.canonicalName)
1765+
val sut = fixture.getSut()
1766+
sut.captureException(IllegalStateException())
1767+
verify(fixture.transport, never()).send(any(), anyOrNull())
1768+
}
1769+
1770+
@Test
1771+
fun `when exception does not match pattern in ignoredExceptions, capturing event sends it`() {
1772+
fixture.sentryOptions.addIgnoredException(IllegalStateException::class.java.canonicalName)
1773+
val sut = fixture.getSut()
1774+
class MyException(message: String) : Exception(message)
1775+
sut.captureException(MyException("hello"))
1776+
verify(fixture.transport).send(any(), anyOrNull())
1777+
}
1778+
1779+
@Test
1780+
fun `when exception matches regex pattern in ignoredExceptions, capturing event does not send it`() {
1781+
fixture.sentryOptions.addIgnoredException("java.lang..*")
1782+
val sut = fixture.getSut()
1783+
sut.captureException(IllegalStateException())
1784+
verify(fixture.transport, never()).send(any(), anyOrNull())
1785+
}
1786+
1787+
@Test
1788+
fun `when exception does not match regex pattern in ignoredExceptions, capturing event sends it`() {
1789+
fixture.sentryOptions.addIgnoredException("java.lang..*")
1790+
val sut = fixture.getSut()
1791+
class MyException(message: String) : Exception(message)
1792+
sut.captureException(MyException("hello"))
1793+
verify(fixture.transport).send(any(), anyOrNull())
1794+
}
1795+
1796+
@Test
1797+
fun `when ignoredExceptionsForType and ignoredExceptions are not explicitly specified, capturing event sends exceptions`() {
1798+
val sut = fixture.getSut()
1799+
sut.captureException(IllegalStateException())
1800+
class MyException(message: String) : Exception(message)
1801+
sut.captureException(MyException("hello"))
1802+
verify(fixture.transport, atLeast(2)).send(any(), anyOrNull())
1803+
}
1804+
17611805
@Test
17621806
fun `screenshot is added to the envelope from the hint`() {
17631807
val sut = fixture.getSut()

0 commit comments

Comments
 (0)