Skip to content

Commit

Permalink
Add option to ignore exceptions by type. (#1352)
Browse files Browse the repository at this point in the history
Fixes #1306
  • Loading branch information
maciejwalkowiak committed Mar 26, 2021
1 parent bc99848 commit 1d778b5
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 167 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,7 @@
# Unreleased

* Feat: Add option to ignore exceptions by type (#1352)

# 4.4.0-alpha.1

* Bump: sentry-native to 0.4.8
Expand Down
Expand Up @@ -109,6 +109,11 @@ static class HubConfiguration {
if (options.getTracesSampleRate() == null) {
options.setTracesSampleRate(0.0);
}
// Spring Boot sets ignored exceptions in runtime using reflection - where the generic
// information is lost
// its technically possible to set non-throwable class to `ignoredExceptionsForType` set
// here we make sure that only classes that extend throwable are set on this field
options.getIgnoredExceptionsForType().removeIf(it -> !Throwable.class.isAssignableFrom(it));
Sentry.init(options);
return HubAdapter.getInstance();
}
Expand Down
Expand Up @@ -27,6 +27,7 @@ import io.sentry.test.checkEvent
import io.sentry.transport.ITransport
import io.sentry.transport.ITransportGate
import io.sentry.transport.apache.ApacheHttpClientTransportFactory
import java.lang.RuntimeException
import javax.servlet.Filter
import kotlin.test.Test
import kotlin.test.assertEquals
Expand Down Expand Up @@ -142,7 +143,8 @@ class SentryAutoConfigurationTest {
"sentry.enable-tracing=true",
"sentry.traces-sample-rate=0.3",
"sentry.tags.tag1=tag1-value",
"sentry.tags.tag2=tag2-value"
"sentry.tags.tag2=tag2-value",
"sentry.ignored-exceptions-for-type=java.lang.RuntimeException,java.lang.IllegalStateException,io.sentry.Sentry"
).run {
val options = it.getBean(SentryProperties::class.java)
assertThat(options.readTimeoutMillis).isEqualTo(10)
Expand All @@ -169,6 +171,7 @@ class SentryAutoConfigurationTest {
assertThat(options.isEnableTracing).isTrue()
assertThat(options.tracesSampleRate).isEqualTo(0.3)
assertThat(options.tags).containsEntry("tag1", "tag1-value").containsEntry("tag2", "tag2-value")
assertThat(options.ignoredExceptionsForType).containsOnly(RuntimeException::class.java, IllegalStateException::class.java)
}
}

Expand Down
4 changes: 3 additions & 1 deletion sentry/api/sentry.api
Expand Up @@ -719,11 +719,12 @@ public final class io/sentry/SentryLevel : java/lang/Enum {
public class io/sentry/SentryOptions {
public fun <init> ()V
public fun addEventProcessor (Lio/sentry/EventProcessor;)V
public fun addIgnoredExceptionForType (Ljava/lang/Class;)V
public fun addInAppExclude (Ljava/lang/String;)V
public fun addInAppInclude (Ljava/lang/String;)V
public fun addIntegration (Lio/sentry/Integration;)V
public fun addScopeObserver (Lio/sentry/IScopeObserver;)V
public static fun from (Lio/sentry/config/PropertiesProvider;)Lio/sentry/SentryOptions;
public static fun from (Lio/sentry/config/PropertiesProvider;Lio/sentry/ILogger;)Lio/sentry/SentryOptions;
public fun getBeforeBreadcrumb ()Lio/sentry/SentryOptions$BeforeBreadcrumbCallback;
public fun getBeforeSend ()Lio/sentry/SentryOptions$BeforeSendCallback;
public fun getCacheDirPath ()Ljava/lang/String;
Expand All @@ -740,6 +741,7 @@ public class io/sentry/SentryOptions {
public fun getEventProcessors ()Ljava/util/List;
public fun getFlushTimeoutMillis ()J
public fun getHostnameVerifier ()Ljavax/net/ssl/HostnameVerifier;
public fun getIgnoredExceptionsForType ()Ljava/util/Set;
public fun getInAppExcludes ()Ljava/util/List;
public fun getInAppIncludes ()Ljava/util/List;
public fun getIntegrations ()Ljava/util/List;
Expand Down
2 changes: 1 addition & 1 deletion sentry/src/main/java/io/sentry/Sentry.java
Expand Up @@ -184,7 +184,7 @@ private static synchronized void init(

private static boolean initConfigurations(final @NotNull SentryOptions options) {
if (options.isEnableExternalConfiguration()) {
options.merge(SentryOptions.from(PropertiesProviderFactory.create()));
options.merge(SentryOptions.from(PropertiesProviderFactory.create(), options.getLogger()));
}

final String dsn = options.getDsn();
Expand Down
14 changes: 12 additions & 2 deletions sentry/src/main/java/io/sentry/SentryClient.java
Expand Up @@ -94,16 +94,26 @@ public boolean isEnabled() {
}
}

SentryId sentryId = SentryId.EMPTY_ID;

if (event != null) {
if (event.getOriginThrowable() != null
&& options.containsIgnoredExceptionForType(event.getOriginThrowable())) {
options
.getLogger()
.log(
SentryLevel.DEBUG,
"Event was dropped as the exception %s is ignored",
event.getOriginThrowable().getClass());
return sentryId;
}
event = executeBeforeSend(event, hint);

if (event == null) {
options.getLogger().log(SentryLevel.DEBUG, "Event was dropped by beforeSend");
}
}

SentryId sentryId = SentryId.EMPTY_ID;

if (event != null) {
sentryId = event.getEventId();
}
Expand Down
66 changes: 65 additions & 1 deletion sentry/src/main/java/io/sentry/SentryOptions.java
Expand Up @@ -10,10 +10,13 @@
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSocketFactory;
import org.jetbrains.annotations.ApiStatus;
Expand All @@ -36,6 +39,10 @@ public class SentryOptions {
*/
private final @NotNull List<EventProcessor> eventProcessors = new CopyOnWriteArrayList<>();

/** Exceptions that once captured will not be sent to Sentry as {@link SentryEvent}. */
private final @NotNull Set<Class<? extends Throwable>> ignoredExceptionsForType =
new CopyOnWriteArraySet<>();

/**
* Code that provides middlewares, bindings or hooks into certain frameworks or environments,
* along with code that inserts those bindings and activates them.
Expand Down Expand Up @@ -267,7 +274,9 @@ public class SentryOptions {
* @param propertiesProvider the properties provider
* @return the sentry options
*/
public static @NotNull SentryOptions from(final @NotNull PropertiesProvider propertiesProvider) {
@SuppressWarnings("unchecked")
public static @NotNull SentryOptions from(
final @NotNull PropertiesProvider propertiesProvider, final @NotNull ILogger logger) {
final SentryOptions options = new SentryOptions();
options.setDsn(propertiesProvider.getProperty("dsn"));
options.setEnvironment(propertiesProvider.getProperty("environment"));
Expand Down Expand Up @@ -299,6 +308,27 @@ public class SentryOptions {
for (final String inAppExclude : propertiesProvider.getList("in-app-excludes")) {
options.addInAppExclude(inAppExclude);
}
for (final String ignoredExceptionType :
propertiesProvider.getList("ignored-exceptions-for-type")) {
try {
Class<?> clazz = Class.forName(ignoredExceptionType);
if (Throwable.class.isAssignableFrom(clazz)) {
options.addIgnoredExceptionForType((Class<? extends Throwable>) clazz);
} else {
logger.log(
SentryLevel.WARNING,
"Skipping setting %s as ignored-exception-for-type. Reason: %s does not extend Throwable",
ignoredExceptionType,
ignoredExceptionType);
}
} catch (ClassNotFoundException e) {
logger.log(
SentryLevel.WARNING,
"Skipping setting %s as ignored-exception-for-type. Reason: %s class is not found",
ignoredExceptionType,
ignoredExceptionType);
}
}
return options;
}

Expand Down Expand Up @@ -1278,6 +1308,36 @@ public boolean isTracingEnabled() {
return getTracesSampleRate() != null || getTracesSampler() != null;
}

/**
* Returns the list of exception classes that once captured will not be sent to Sentry as {@link
* SentryEvent}.
*
* @return the list of exception classes that once captured will not be sent to Sentry as {@link
* SentryEvent}.
*/
public @NotNull Set<Class<? extends Throwable>> getIgnoredExceptionsForType() {
return ignoredExceptionsForType;
}

/**
* Adds exception type to the list of ignored exceptions.
*
* @param exceptionType - the exception type
*/
public void addIgnoredExceptionForType(final @NotNull Class<? extends Throwable> exceptionType) {
this.ignoredExceptionsForType.add(exceptionType);
}

/**
* Checks if the type of exception given by parameter is ignored.
*
* @param throwable the throwable
* @return if the type of exception is ignored
*/
boolean containsIgnoredExceptionForType(final @NotNull Throwable throwable) {
return this.ignoredExceptionsForType.contains(throwable.getClass());
}

/** The BeforeSend callback */
public interface BeforeSendCallback {

Expand Down Expand Up @@ -1410,6 +1470,10 @@ void merge(final @NotNull SentryOptions options) {
for (final String inAppExclude : inAppExcludes) {
addInAppExclude(inAppExclude);
}
for (final Class<? extends Throwable> exceptionType :
new HashSet<>(options.getIgnoredExceptionsForType())) {
addIgnoredExceptionForType(exceptionType);
}
}

private @NotNull SdkVersion createSdkVersion() {
Expand Down
10 changes: 10 additions & 0 deletions sentry/src/test/java/io/sentry/SentryClientTest.kt
Expand Up @@ -10,6 +10,7 @@ import com.nhaarman.mockitokotlin2.mockingDetails
import com.nhaarman.mockitokotlin2.never
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions
import com.nhaarman.mockitokotlin2.verifyZeroInteractions
import com.nhaarman.mockitokotlin2.whenever
import io.sentry.exception.InvalidDsnException
import io.sentry.exception.SentryEnvelopeException
Expand All @@ -29,6 +30,7 @@ import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.InputStreamReader
import java.lang.IllegalStateException
import java.lang.RuntimeException
import java.nio.charset.Charset
import java.util.Arrays
Expand Down Expand Up @@ -903,6 +905,14 @@ class SentryClientTest {
assertEquals("abc", transaction.platform)
}

@Test
fun `when exception type is ignored, capturing event does not send it`() {
fixture.sentryOptions.addIgnoredExceptionForType(IllegalStateException::class.java)
val sut = fixture.getSut()
sut.captureException(IllegalStateException())
verifyZeroInteractions(fixture.transport)
}

private fun createScope(): Scope {
return Scope(SentryOptions()).apply {
addBreadcrumb(Breadcrumb().apply {
Expand Down

0 comments on commit 1d778b5

Please sign in to comment.