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 @@ -15,6 +15,7 @@

### Fixes

- Add opt-in support for matching GraphQL ignored error types against classification specifications via `sentry.graphql.enable-specification-error-type-filtering` ([#6092](https://github.com/getsentry/sentry-java/pull/6092))
- Session Replay: Fix `SentryOkHttpInterceptor` hanging forever on responses whose body has no known length, such as Server-Sent Events or a gzipped response, when network details are enabled for the URL ([#6231](https://github.com/getsentry/sentry-java/pull/6231))
- Stop marking an OkHttp call span as failed when a connection attempt to one of the host's addresses fails but OkHttp connects on another ([#6472](https://github.com/getsentry/sentry-java/pull/6472))

Expand Down
2 changes: 2 additions & 0 deletions sentry-graphql-22/api/sentry-graphql-22.api
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ public final class io/sentry/graphql22/SentryInstrumentation : graphql/execution
public static final field SENTRY_EXCEPTIONS_CONTEXT_KEY Ljava/lang/String;
public static final field SENTRY_SCOPES_CONTEXT_KEY Ljava/lang/String;
public fun <init> (Lio/sentry/graphql/SentryGraphqlInstrumentation$BeforeSpanCallback;Lio/sentry/graphql/SentrySubscriptionHandler;Lio/sentry/graphql/ExceptionReporter;Ljava/util/List;)V
public fun <init> (Lio/sentry/graphql/SentryGraphqlInstrumentation$BeforeSpanCallback;Lio/sentry/graphql/SentrySubscriptionHandler;Lio/sentry/graphql/ExceptionReporter;Ljava/util/List;Z)V
public fun <init> (Lio/sentry/graphql/SentryGraphqlInstrumentation$BeforeSpanCallback;Lio/sentry/graphql/SentrySubscriptionHandler;Z)V
public fun <init> (Lio/sentry/graphql/SentryGraphqlInstrumentation$BeforeSpanCallback;Lio/sentry/graphql/SentrySubscriptionHandler;ZLjava/util/List;)V
public fun <init> (Lio/sentry/graphql/SentryGraphqlInstrumentation$BeforeSpanCallback;Lio/sentry/graphql/SentrySubscriptionHandler;ZLjava/util/List;Z)V
public fun <init> (Lio/sentry/graphql/SentrySubscriptionHandler;Z)V
public fun beginExecuteOperation (Lgraphql/execution/instrumentation/parameters/InstrumentationExecuteOperationParameters;Lgraphql/execution/instrumentation/InstrumentationState;)Lgraphql/execution/instrumentation/InstrumentationContext;
public fun beginExecution (Lgraphql/execution/instrumentation/parameters/InstrumentationExecutionParameters;Lgraphql/execution/instrumentation/InstrumentationState;)Lgraphql/execution/instrumentation/InstrumentationContext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,35 @@ public SentryInstrumentation(
final @NotNull SentrySubscriptionHandler subscriptionHandler,
final boolean captureRequestBodyForNonSubscriptions,
final @NotNull List<String> ignoredErrorTypes) {
this(
beforeSpan,
subscriptionHandler,
captureRequestBodyForNonSubscriptions,
ignoredErrorTypes,
false);
}

/**
* @param beforeSpan callback when a span is created
* @param subscriptionHandler can report subscription errors
* @param captureRequestBodyForNonSubscriptions false if request bodies should not be captured by
* this integration for query and mutation operations
* @param ignoredErrorTypes list of error types that should not be captured and sent to Sentry
* @param enableSpecificationErrorTypeFiltering whether ignored error types should also be matched
* against {@link graphql.ErrorClassification#toSpecification(graphql.GraphQLError)}
*/
public SentryInstrumentation(
final @Nullable SentryGraphqlInstrumentation.BeforeSpanCallback beforeSpan,
final @NotNull SentrySubscriptionHandler subscriptionHandler,
final boolean captureRequestBodyForNonSubscriptions,
final @NotNull List<String> ignoredErrorTypes,
final boolean enableSpecificationErrorTypeFiltering) {
this(
beforeSpan,
subscriptionHandler,
new ExceptionReporter(captureRequestBodyForNonSubscriptions),
ignoredErrorTypes);
ignoredErrorTypes,
enableSpecificationErrorTypeFiltering);
}

@TestOnly
Expand All @@ -90,9 +114,24 @@ public SentryInstrumentation(
final @NotNull SentrySubscriptionHandler subscriptionHandler,
final @NotNull ExceptionReporter exceptionReporter,
final @NotNull List<String> ignoredErrorTypes) {
this(beforeSpan, subscriptionHandler, exceptionReporter, ignoredErrorTypes, false);
}

@TestOnly
public SentryInstrumentation(
final @Nullable SentryGraphqlInstrumentation.BeforeSpanCallback beforeSpan,
final @NotNull SentrySubscriptionHandler subscriptionHandler,
final @NotNull ExceptionReporter exceptionReporter,
final @NotNull List<String> ignoredErrorTypes,
final boolean enableSpecificationErrorTypeFiltering) {
this.instrumentation =
new SentryGraphqlInstrumentation(
beforeSpan, subscriptionHandler, exceptionReporter, ignoredErrorTypes, TRACE_ORIGIN);
beforeSpan,
subscriptionHandler,
exceptionReporter,
ignoredErrorTypes,
enableSpecificationErrorTypeFiltering,
TRACE_ORIGIN);
SentryIntegrationPackageStorage.getInstance().addIntegration("GraphQL-v22");
}

Expand Down
2 changes: 2 additions & 0 deletions sentry-graphql-core/api/sentry-graphql-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ public final class io/sentry/graphql/SentryGraphqlInstrumentation {
public static final field SENTRY_EXCEPTIONS_CONTEXT_KEY Ljava/lang/String;
public static final field SENTRY_SCOPES_CONTEXT_KEY Ljava/lang/String;
public fun <init> (Lio/sentry/graphql/SentryGraphqlInstrumentation$BeforeSpanCallback;Lio/sentry/graphql/SentrySubscriptionHandler;Lio/sentry/graphql/ExceptionReporter;Ljava/util/List;Ljava/lang/String;)V
public fun <init> (Lio/sentry/graphql/SentryGraphqlInstrumentation$BeforeSpanCallback;Lio/sentry/graphql/SentrySubscriptionHandler;Lio/sentry/graphql/ExceptionReporter;Ljava/util/List;ZLjava/lang/String;)V
public fun <init> (Lio/sentry/graphql/SentryGraphqlInstrumentation$BeforeSpanCallback;Lio/sentry/graphql/SentrySubscriptionHandler;ZLjava/util/List;Ljava/lang/String;)V
public fun <init> (Lio/sentry/graphql/SentryGraphqlInstrumentation$BeforeSpanCallback;Lio/sentry/graphql/SentrySubscriptionHandler;ZLjava/util/List;ZLjava/lang/String;)V
public fun beginExecuteOperation (Lgraphql/execution/instrumentation/parameters/InstrumentationExecuteOperationParameters;)V
public fun beginExecution (Lgraphql/execution/instrumentation/parameters/InstrumentationExecutionParameters;Lio/sentry/graphql/SentryGraphqlInstrumentation$TracingState;)V
public fun createState ()Lgraphql/execution/instrumentation/InstrumentationState;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public final class SentryGraphqlInstrumentation {
private final @NotNull SentrySubscriptionHandler subscriptionHandler;
private final @NotNull ExceptionReporter exceptionReporter;
private final @NotNull List<String> ignoredErrorTypes;
private final boolean enableSpecificationErrorTypeFiltering;
private final @NotNull String traceOrigin;

/**
Expand All @@ -72,11 +73,38 @@ public SentryGraphqlInstrumentation(
final boolean captureRequestBodyForNonSubscriptions,
final @NotNull List<String> ignoredErrorTypes,
final @NotNull String traceOrigin) {
this(
beforeSpan,
subscriptionHandler,
captureRequestBodyForNonSubscriptions,
ignoredErrorTypes,
false,
traceOrigin);
}

/**
* @param beforeSpan callback when a span is created
* @param subscriptionHandler can report subscription errors
* @param captureRequestBodyForNonSubscriptions false if request bodies should not be captured by
* this integration for query and mutation operations
* @param ignoredErrorTypes list of error types that should not be captured and sent to Sentry
* @param enableSpecificationErrorTypeFiltering whether ignored error types should also be matched
* against {@link ErrorClassification#toSpecification(GraphQLError)}
* @param traceOrigin origin used for spans created by this integration
*/
public SentryGraphqlInstrumentation(
final @Nullable BeforeSpanCallback beforeSpan,
final @NotNull SentrySubscriptionHandler subscriptionHandler,
final boolean captureRequestBodyForNonSubscriptions,
final @NotNull List<String> ignoredErrorTypes,
final boolean enableSpecificationErrorTypeFiltering,
final @NotNull String traceOrigin) {
this(
beforeSpan,
subscriptionHandler,
new ExceptionReporter(captureRequestBodyForNonSubscriptions),
ignoredErrorTypes,
enableSpecificationErrorTypeFiltering,
traceOrigin);
}

Expand All @@ -87,10 +115,22 @@ public SentryGraphqlInstrumentation(
final @NotNull ExceptionReporter exceptionReporter,
final @NotNull List<String> ignoredErrorTypes,
final @NotNull String traceOrigin) {
this(beforeSpan, subscriptionHandler, exceptionReporter, ignoredErrorTypes, false, traceOrigin);
}

@TestOnly
public SentryGraphqlInstrumentation(
final @Nullable BeforeSpanCallback beforeSpan,
final @NotNull SentrySubscriptionHandler subscriptionHandler,
final @NotNull ExceptionReporter exceptionReporter,
final @NotNull List<String> ignoredErrorTypes,
final boolean enableSpecificationErrorTypeFiltering,
final @NotNull String traceOrigin) {
this.beforeSpan = beforeSpan;
this.subscriptionHandler = subscriptionHandler;
this.exceptionReporter = exceptionReporter;
this.ignoredErrorTypes = ignoredErrorTypes;
this.enableSpecificationErrorTypeFiltering = enableSpecificationErrorTypeFiltering;
this.traceOrigin = traceOrigin;
}

Expand Down Expand Up @@ -127,8 +167,7 @@ public void instrumentExecutionResultComplete(
final @NotNull List<GraphQLError> errors = result.getErrors();
if (errors != null) {
for (GraphQLError error : errors) {
String errorType = getErrorType(error);
if (!isIgnored(errorType)) {
if (!isIgnored(error)) {
exceptionReporter.captureThrowable(
new RuntimeException(error.getMessage()),
new ExceptionReporter.ExceptionDetails(
Expand Down Expand Up @@ -158,19 +197,38 @@ private boolean isIgnored(final @Nullable String errorType) {
|| ignoredErrorTypes.contains(errorType);
}

private @Nullable String getErrorType(final @Nullable GraphQLError error) {
private boolean isIgnored(final @Nullable GraphQLError error) {
if (error == null) {
return null;
return false;
}
final @Nullable ErrorClassification errorType = error.getErrorType();
if (errorType != null) {
return errorType.toString();
if (isIgnored(errorType.toString())) {
return true;
}
if (!enableSpecificationErrorTypeFiltering) {
return false;
}
try {
final @Nullable Object specification = errorType.toSpecification(error);
if (specification instanceof String && isIgnored((String) specification)) {
return true;
}
if (specification instanceof Map) {
final @Nullable Object specificationType = ((Map<?, ?>) specification).get("type");
return specificationType instanceof String && isIgnored((String) specificationType);
}
} catch (Throwable throwable) {
ExceptionUtils.rethrowIfFatal(throwable);
// Fall back to capturing the error if a custom classification cannot be serialized.
}
return false;
}
final @Nullable Map<String, Object> extensions = error.getExtensions();
if (extensions != null) {
return StringUtils.toString(extensions.get("errorType"));
return isIgnored(StringUtils.toString(extensions.get("errorType")));
}
return null;
return false;
}

public void beginExecuteOperation(
Expand Down
Loading
Loading