Skip to content

Commit c2a20cb

Browse files
committed
Add options.ignoreExceptions accepting String and Regex
1 parent fc52a26 commit c2a20cb

File tree

7 files changed

+145
-15
lines changed

7 files changed

+145
-15
lines changed

sentry/api/sentry.api

Lines changed: 6 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

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

Lines changed: 21 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,10 @@ public final class ExternalOptions {
130128
}
131129
options.setIdleTimeout(propertiesProvider.getLongProperty("idle-timeout"));
132130

131+
for (final String pattern : propertiesProvider.getList("ignored-exceptions")) {
132+
options.addIgnoredException(pattern);
133+
}
134+
133135
options.setEnabled(propertiesProvider.getBooleanProperty("enabled"));
134136

135137
options.setEnablePrettySerializationOutput(
@@ -373,6 +375,21 @@ public void setIdleTimeout(final @Nullable Long idleTimeout) {
373375
this.idleTimeout = idleTimeout;
374376
}
375377

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

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

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -103,17 +103,42 @@ private boolean shouldApplyScopeData(final @NotNull CheckIn event, final @NotNul
103103

104104
if (event != null) {
105105
final Throwable eventThrowable = event.getThrowable();
106-
if (eventThrowable != null && options.containsIgnoredExceptionForType(eventThrowable)) {
107-
options
108-
.getLogger()
109-
.log(
110-
SentryLevel.DEBUG,
111-
"Event was dropped as the exception %s is ignored",
112-
eventThrowable.getClass());
113-
options
114-
.getClientReportRecorder()
115-
.recordLostEvent(DiscardReason.EVENT_PROCESSOR, DataCategory.Error);
116-
return SentryId.EMPTY_ID;
106+
if (eventThrowable != null) {
107+
if (options.containsIgnoredExceptionForType(eventThrowable)) {
108+
options
109+
.getLogger()
110+
.log(
111+
SentryLevel.DEBUG,
112+
"Event was dropped as the exception %s is ignored",
113+
eventThrowable.getClass());
114+
options
115+
.getClientReportRecorder()
116+
.recordLostEvent(DiscardReason.EVENT_PROCESSOR, DataCategory.Error);
117+
return SentryId.EMPTY_ID;
118+
}
119+
120+
final List<FilterString> ignoredExceptions = options.getIgnoredExceptions();
121+
if (ignoredExceptions != null) {
122+
final String throwableClassName = eventThrowable.getClass().getCanonicalName();
123+
if (throwableClassName != null) {
124+
for (final FilterString filter : ignoredExceptions) {
125+
if (filter.getFilterString().equals(throwableClassName)
126+
|| filter.matches(throwableClassName)) {
127+
options
128+
.getLogger()
129+
.log(
130+
SentryLevel.DEBUG,
131+
"Event was dropped as the exception %s matches the ignoreExceptions filter pattern %s",
132+
throwableClassName,
133+
filter.getFilterString());
134+
options
135+
.getClientReportRecorder()
136+
.recordLostEvent(DiscardReason.EVENT_PROCESSOR, DataCategory.Error);
137+
return SentryId.EMPTY_ID;
138+
}
139+
}
140+
}
141+
}
117142
}
118143
}
119144

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/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: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,6 +1758,40 @@ class SentryClientTest {
17581758
verify(fixture.transport, never()).send(any(), anyOrNull())
17591759
}
17601760

1761+
@Test
1762+
fun `when exception matches pattern in ignoredExceptions, capturing event does not send it`() {
1763+
fixture.sentryOptions.addIgnoredException(IllegalStateException::class.java.canonicalName)
1764+
val sut = fixture.getSut()
1765+
sut.captureException(IllegalStateException())
1766+
verify(fixture.transport, never()).send(any(), anyOrNull())
1767+
}
1768+
1769+
@Test
1770+
fun `when exception does not match pattern in ignoredExceptions, capturing event sends it`() {
1771+
fixture.sentryOptions.addIgnoredException(IllegalStateException::class.java.canonicalName)
1772+
val sut = fixture.getSut()
1773+
class MyException(message: String) : Exception(message)
1774+
sut.captureException(MyException("hello"))
1775+
verify(fixture.transport).send(any(), anyOrNull())
1776+
}
1777+
1778+
@Test
1779+
fun `when exception matches regex pattern in ignoredExceptions, capturing event does not send it`() {
1780+
fixture.sentryOptions.addIgnoredException("java.lang..*")
1781+
val sut = fixture.getSut()
1782+
sut.captureException(IllegalStateException())
1783+
verify(fixture.transport, never()).send(any(), anyOrNull())
1784+
}
1785+
1786+
@Test
1787+
fun `when exception does not match regex pattern in ignoredExceptions, capturing event sends it`() {
1788+
fixture.sentryOptions.addIgnoredException("java.lang..*")
1789+
val sut = fixture.getSut()
1790+
class MyException(message: String) : Exception(message)
1791+
sut.captureException(MyException("hello"))
1792+
verify(fixture.transport).send(any(), anyOrNull())
1793+
}
1794+
17611795
@Test
17621796
fun `screenshot is added to the envelope from the hint`() {
17631797
val sut = fixture.getSut()

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ class SentryOptionsTest {
326326
externalOptions.isSendModules = false
327327
externalOptions.ignoredCheckIns = listOf("slug1", "slug-B")
328328
externalOptions.ignoredTransactions = listOf("transactionName1", "transaction-name-B")
329+
externalOptions.ignoredExceptions = listOf("com.some.Exception1", "com.some.Exception2")
329330
externalOptions.isEnableBackpressureHandling = false
330331
externalOptions.maxRequestBodySize = SentryOptions.RequestSize.MEDIUM
331332
externalOptions.isSendDefaultPii = true
@@ -370,6 +371,7 @@ class SentryOptionsTest {
370371
assertFalse(options.isSendModules)
371372
assertEquals(listOf(FilterString("slug1"), FilterString("slug-B")), options.ignoredCheckIns)
372373
assertEquals(listOf(FilterString("transactionName1"), FilterString("transaction-name-B")), options.ignoredTransactions)
374+
assertEquals(listOf(FilterString("com.some.Exception1"), FilterString("com.some.Exception2")), options.ignoredExceptions)
373375
assertFalse(options.isEnableBackpressureHandling)
374376
assertTrue(options.isForceInit)
375377
assertNotNull(options.cron)

0 commit comments

Comments
 (0)