Skip to content

Commit

Permalink
Replace GraphQlSourceBuilderCustomizer with directly providing a `S…
Browse files Browse the repository at this point in the history
…entryInstrumenter` bean if missing (#3744)

* attach request body for application/x-www-form-urlencoded

* extend tests

* changelog

* Add support for v22 of graphql-java, new modules sentry-graphql-22 and sentry-graphql-core

* Add back callback interface and constants as deprecated

* Replace GraphQlSourceBuilderCustomizer with directly providing a SentryInstrumentation bean if missing

* CR changes; changelog
  • Loading branch information
adinauer authored Oct 7, 2024
1 parent 18da8f8 commit 093ebc6
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 76 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
- Support `graphql-java` v22 via a new module `sentry-graphql-22` ([#3740](https://github.com/getsentry/sentry-java/pull/3740))
- If you are using `graphql-java` v21 or earlier, you can use the `sentry-graphql` module
- For `graphql-java` v22 and newer please use the `sentry-graphql-22` module
- We now provide a `SentryInstrumenter` bean directly for Spring (Boot) if there is none yet instead of using `GraphQlSourceBuilderCustomizer` to add the instrumentation ([#3744](https://github.com/getsentry/sentry-java/pull/3744))
- It is now also possible to provide a bean of type `SentryGraphqlInstrumentation.BeforeSpanCallback` which is then used by `SentryInstrumenter`

### Fixes

Expand Down
1 change: 1 addition & 0 deletions sentry-graphql-22/api/sentry-graphql-22.api
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
public final class io/sentry/graphql22/BuildConfig {
public static final field SENTRY_GRAPHQL_SDK_NAME Ljava/lang/String;
public static final field SENTRY_GRAPHQL22_SDK_NAME Ljava/lang/String;
public static final field VERSION_NAME Ljava/lang/String;
}
Expand Down
12 changes: 10 additions & 2 deletions sentry-spring-boot-jakarta/api/sentry-spring-boot-jakarta.api
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,19 @@ public class io/sentry/spring/boot/jakarta/SentryWebfluxAutoConfiguration {
public fun sentryWebExceptionHandler (Lio/sentry/IScopes;)Lio/sentry/spring/jakarta/webflux/SentryWebExceptionHandler;
}

public class io/sentry/spring/boot/jakarta/graphql/SentryGraphql22AutoConfiguration {
public fun <init> ()V
public fun exceptionResolverAdapter ()Lio/sentry/spring/jakarta/graphql/SentryDataFetcherExceptionResolverAdapter;
public static fun graphqlBeanPostProcessor ()Lio/sentry/spring/jakarta/graphql/SentryGraphqlBeanPostProcessor;
public fun sentryInstrumentationWebMvc (Lio/sentry/spring/boot/jakarta/SentryProperties;Lorg/springframework/beans/factory/ObjectProvider;)Lio/sentry/graphql22/SentryInstrumentation;
public fun sentryInstrumentationWebflux (Lio/sentry/spring/boot/jakarta/SentryProperties;Lorg/springframework/beans/factory/ObjectProvider;)Lio/sentry/graphql22/SentryInstrumentation;
}

public class io/sentry/spring/boot/jakarta/graphql/SentryGraphqlAutoConfiguration {
public fun <init> ()V
public fun exceptionResolverAdapter ()Lio/sentry/spring/jakarta/graphql/SentryDataFetcherExceptionResolverAdapter;
public static fun graphqlBeanPostProcessor ()Lio/sentry/spring/jakarta/graphql/SentryGraphqlBeanPostProcessor;
public fun sourceBuilderCustomizerWebflux (Lio/sentry/spring/boot/jakarta/SentryProperties;)Lorg/springframework/boot/autoconfigure/graphql/GraphQlSourceBuilderCustomizer;
public fun sourceBuilderCustomizerWebmvc (Lio/sentry/spring/boot/jakarta/SentryProperties;)Lorg/springframework/boot/autoconfigure/graphql/GraphQlSourceBuilderCustomizer;
public fun sentryInstrumentationWebMvc (Lio/sentry/spring/boot/jakarta/SentryProperties;Lorg/springframework/beans/factory/ObjectProvider;)Lio/sentry/graphql/SentryInstrumentation;
public fun sentryInstrumentationWebflux (Lio/sentry/spring/boot/jakarta/SentryProperties;Lorg/springframework/beans/factory/ObjectProvider;)Lio/sentry/graphql/SentryInstrumentation;
}

Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

import com.jakewharton.nopen.annotation.Open;
import io.sentry.SentryIntegrationPackageStorage;
import io.sentry.graphql.SentryGraphqlInstrumentation;
import io.sentry.graphql.SentryInstrumentation;
import io.sentry.spring.boot.jakarta.SentryProperties;
import io.sentry.spring.jakarta.graphql.SentryDataFetcherExceptionResolverAdapter;
import io.sentry.spring.jakarta.graphql.SentryGraphqlBeanPostProcessor;
import io.sentry.spring.jakarta.graphql.SentrySpringSubscriptionHandler;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.graphql.GraphQlSourceBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
Expand All @@ -19,37 +21,42 @@
@Open
public class SentryGraphqlAutoConfiguration {

@Bean
@Bean(name = "sentryInstrumentation")
@ConditionalOnMissingBean
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public GraphQlSourceBuilderCustomizer sourceBuilderCustomizerWebmvc(
final @NotNull SentryProperties sentryProperties) {
public SentryInstrumentation sentryInstrumentationWebMvc(
final @NotNull SentryProperties sentryProperties,
final @NotNull ObjectProvider<SentryGraphqlInstrumentation.BeforeSpanCallback>
beforeSpanCallback) {
SentryIntegrationPackageStorage.getInstance().addIntegration("Spring6GrahQLWebMVC");
return sourceBuilderCustomizer(sentryProperties, false);
return createInstrumentation(sentryProperties, beforeSpanCallback, false);
}

@Bean
@Bean(name = "sentryInstrumentation")
@ConditionalOnMissingBean
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public GraphQlSourceBuilderCustomizer sourceBuilderCustomizerWebflux(
final @NotNull SentryProperties sentryProperties) {
public SentryInstrumentation sentryInstrumentationWebflux(
final @NotNull SentryProperties sentryProperties,
final @NotNull ObjectProvider<SentryGraphqlInstrumentation.BeforeSpanCallback>
beforeSpanCallback) {
SentryIntegrationPackageStorage.getInstance().addIntegration("Spring6GrahQLWebFlux");
return sourceBuilderCustomizer(sentryProperties, true);
return createInstrumentation(sentryProperties, beforeSpanCallback, true);
}

/**
* We're not setting defaultDataFetcherExceptionHandler here on purpose and instead use the
* resolver adapter below. This way Springs handler can still forward to other resolver adapters.
*/
private GraphQlSourceBuilderCustomizer sourceBuilderCustomizer(
final @NotNull SentryProperties sentryProperties, final boolean captureRequestBody) {
return (builder) ->
builder.configureGraphQl(
graphQlBuilder ->
graphQlBuilder.instrumentation(
new SentryInstrumentation(
null,
new SentrySpringSubscriptionHandler(),
captureRequestBody,
sentryProperties.getGraphql().getIgnoredErrorTypes())));
private SentryInstrumentation createInstrumentation(
final @NotNull SentryProperties sentryProperties,
final @NotNull ObjectProvider<SentryGraphqlInstrumentation.BeforeSpanCallback>
beforeSpanCallback,
final boolean captureRequestBody) {
return new SentryInstrumentation(
beforeSpanCallback.getIfAvailable(),
new SentrySpringSubscriptionHandler(),
captureRequestBody,
sentryProperties.getGraphql().getIgnoredErrorTypes());
}

@Bean
Expand Down
4 changes: 2 additions & 2 deletions sentry-spring-boot/api/sentry-spring-boot.api
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public class io/sentry/spring/boot/graphql/SentryGraphqlAutoConfiguration {
public fun <init> ()V
public fun exceptionResolverAdapter ()Lio/sentry/spring/graphql/SentryDataFetcherExceptionResolverAdapter;
public static fun graphqlBeanPostProcessor ()Lio/sentry/spring/graphql/SentryGraphqlBeanPostProcessor;
public fun sourceBuilderCustomizerWebflux (Lio/sentry/spring/boot/SentryProperties;)Lorg/springframework/boot/autoconfigure/graphql/GraphQlSourceBuilderCustomizer;
public fun sourceBuilderCustomizerWebmvc (Lio/sentry/spring/boot/SentryProperties;)Lorg/springframework/boot/autoconfigure/graphql/GraphQlSourceBuilderCustomizer;
public fun sentryInstrumentationWebMvc (Lio/sentry/spring/boot/SentryProperties;Lorg/springframework/beans/factory/ObjectProvider;)Lio/sentry/graphql/SentryInstrumentation;
public fun sentryInstrumentationWebflux (Lio/sentry/spring/boot/SentryProperties;Lorg/springframework/beans/factory/ObjectProvider;)Lio/sentry/graphql/SentryInstrumentation;
}

Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

import com.jakewharton.nopen.annotation.Open;
import io.sentry.SentryIntegrationPackageStorage;
import io.sentry.graphql.SentryGraphqlInstrumentation;
import io.sentry.graphql.SentryInstrumentation;
import io.sentry.spring.boot.SentryProperties;
import io.sentry.spring.graphql.SentryDataFetcherExceptionResolverAdapter;
import io.sentry.spring.graphql.SentryGraphqlBeanPostProcessor;
import io.sentry.spring.graphql.SentrySpringSubscriptionHandler;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.graphql.GraphQlSourceBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
Expand All @@ -19,37 +21,42 @@
@Open
public class SentryGraphqlAutoConfiguration {

@Bean
@Bean(name = "sentryInstrumentation")
@ConditionalOnMissingBean
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public GraphQlSourceBuilderCustomizer sourceBuilderCustomizerWebmvc(
final @NotNull SentryProperties sentryProperties) {
public SentryInstrumentation sentryInstrumentationWebMvc(
final @NotNull SentryProperties sentryProperties,
final @NotNull ObjectProvider<SentryGraphqlInstrumentation.BeforeSpanCallback>
beforeSpanCallback) {
SentryIntegrationPackageStorage.getInstance().addIntegration("Spring5GrahQLWebMVC");
return sourceBuilderCustomizer(sentryProperties, false);
return createInstrumentation(sentryProperties, beforeSpanCallback, false);
}

@Bean
@Bean(name = "sentryInstrumentation")
@ConditionalOnMissingBean
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public GraphQlSourceBuilderCustomizer sourceBuilderCustomizerWebflux(
final @NotNull SentryProperties sentryProperties) {
public SentryInstrumentation sentryInstrumentationWebflux(
final @NotNull SentryProperties sentryProperties,
final @NotNull ObjectProvider<SentryGraphqlInstrumentation.BeforeSpanCallback>
beforeSpanCallback) {
SentryIntegrationPackageStorage.getInstance().addIntegration("Spring5GrahQLWebFlux");
return sourceBuilderCustomizer(sentryProperties, true);
return createInstrumentation(sentryProperties, beforeSpanCallback, true);
}

/**
* We're not setting defaultDataFetcherExceptionHandler here on purpose and instead use the
* resolver adapter below. This way Springs handler can still forward to other resolver adapters.
*/
private GraphQlSourceBuilderCustomizer sourceBuilderCustomizer(
final @NotNull SentryProperties sentryProperties, final boolean captureRequestBody) {
return (builder) ->
builder.configureGraphQl(
graphQlBuilder ->
graphQlBuilder.instrumentation(
new SentryInstrumentation(
null,
new SentrySpringSubscriptionHandler(),
captureRequestBody,
sentryProperties.getGraphql().getIgnoredErrorTypes())));
private SentryInstrumentation createInstrumentation(
final @NotNull SentryProperties sentryProperties,
final @NotNull ObjectProvider<SentryGraphqlInstrumentation.BeforeSpanCallback>
beforeSpanCallback,
final boolean captureRequestBody) {
return new SentryInstrumentation(
beforeSpanCallback.getIfAvailable(),
new SentrySpringSubscriptionHandler(),
captureRequestBody,
sentryProperties.getGraphql().getIgnoredErrorTypes());
}

@Bean
Expand Down
4 changes: 2 additions & 2 deletions sentry-spring-jakarta/api/sentry-spring-jakarta.api
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,8 @@ public class io/sentry/spring/jakarta/graphql/SentryGraphqlConfiguration {
public fun <init> ()V
public fun exceptionResolverAdapter ()Lio/sentry/spring/jakarta/graphql/SentryDataFetcherExceptionResolverAdapter;
public fun graphqlBeanPostProcessor ()Lio/sentry/spring/jakarta/graphql/SentryGraphqlBeanPostProcessor;
public fun sourceBuilderCustomizerWebflux ()Lorg/springframework/boot/autoconfigure/graphql/GraphQlSourceBuilderCustomizer;
public fun sourceBuilderCustomizerWebmvc ()Lorg/springframework/boot/autoconfigure/graphql/GraphQlSourceBuilderCustomizer;
public fun sentryInstrumentationWebMvc (Lorg/springframework/beans/factory/ObjectProvider;)Lio/sentry/graphql/SentryInstrumentation;
public fun sentryInstrumentationWebflux (Lorg/springframework/beans/factory/ObjectProvider;)Lio/sentry/graphql/SentryInstrumentation;
}

public final class io/sentry/spring/jakarta/graphql/SentrySpringSubscriptionHandler : io/sentry/graphql/SentrySubscriptionHandler {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

import com.jakewharton.nopen.annotation.Open;
import io.sentry.SentryIntegrationPackageStorage;
import io.sentry.graphql.SentryGraphqlInstrumentation;
import io.sentry.graphql.SentryInstrumentation;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.graphql.GraphQlSourceBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
Expand All @@ -14,31 +17,38 @@
@Open
public class SentryGraphqlConfiguration {

@Bean
@Bean(name = "sentryInstrumentation")
@ConditionalOnMissingBean
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public GraphQlSourceBuilderCustomizer sourceBuilderCustomizerWebmvc() {
public SentryInstrumentation sentryInstrumentationWebMvc(
final @NotNull ObjectProvider<SentryGraphqlInstrumentation.BeforeSpanCallback>
beforeSpanCallback) {
SentryIntegrationPackageStorage.getInstance().addIntegration("Spring6GrahQLWebMVC");
return sourceBuilderCustomizer(false);
return createInstrumentation(beforeSpanCallback, false);
}

@Bean
@Bean(name = "sentryInstrumentation")
@ConditionalOnMissingBean
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public GraphQlSourceBuilderCustomizer sourceBuilderCustomizerWebflux() {
public SentryInstrumentation sentryInstrumentationWebflux(
final @NotNull ObjectProvider<SentryGraphqlInstrumentation.BeforeSpanCallback>
beforeSpanCallback) {
SentryIntegrationPackageStorage.getInstance().addIntegration("Spring6GrahQLWebFlux");
return sourceBuilderCustomizer(true);
return createInstrumentation(beforeSpanCallback, true);
}

/**
* We're not setting defaultDataFetcherExceptionHandler here on purpose and instead use the
* resolver adapter below. This way Springs handler can still forward to other resolver adapters.
*/
private GraphQlSourceBuilderCustomizer sourceBuilderCustomizer(final boolean captureRequestBody) {
return (builder) ->
builder.configureGraphQl(
graphQlBuilder ->
graphQlBuilder.instrumentation(
new SentryInstrumentation(
null, new SentrySpringSubscriptionHandler(), captureRequestBody)));
private SentryInstrumentation createInstrumentation(
final @NotNull ObjectProvider<SentryGraphqlInstrumentation.BeforeSpanCallback>
beforeSpanCallback,
final boolean captureRequestBody) {
return new SentryInstrumentation(
beforeSpanCallback.getIfAvailable(),
new SentrySpringSubscriptionHandler(),
captureRequestBody);
}

@Bean
Expand Down
4 changes: 2 additions & 2 deletions sentry-spring/api/sentry-spring.api
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,8 @@ public class io/sentry/spring/graphql/SentryGraphqlConfiguration {
public fun <init> ()V
public fun exceptionResolverAdapter ()Lio/sentry/spring/graphql/SentryDataFetcherExceptionResolverAdapter;
public fun graphqlBeanPostProcessor ()Lio/sentry/spring/graphql/SentryGraphqlBeanPostProcessor;
public fun sourceBuilderCustomizerWebflux ()Lorg/springframework/boot/autoconfigure/graphql/GraphQlSourceBuilderCustomizer;
public fun sourceBuilderCustomizerWebmvc ()Lorg/springframework/boot/autoconfigure/graphql/GraphQlSourceBuilderCustomizer;
public fun sentryInstrumentationWebMvc (Lorg/springframework/beans/factory/ObjectProvider;)Lio/sentry/graphql/SentryInstrumentation;
public fun sentryInstrumentationWebflux (Lorg/springframework/beans/factory/ObjectProvider;)Lio/sentry/graphql/SentryInstrumentation;
}

public final class io/sentry/spring/graphql/SentrySpringSubscriptionHandler : io/sentry/graphql/SentrySubscriptionHandler {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

import com.jakewharton.nopen.annotation.Open;
import io.sentry.SentryIntegrationPackageStorage;
import io.sentry.graphql.SentryGraphqlInstrumentation;
import io.sentry.graphql.SentryInstrumentation;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.graphql.GraphQlSourceBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
Expand All @@ -14,31 +17,38 @@
@Open
public class SentryGraphqlConfiguration {

@Bean
@Bean(name = "sentryInstrumentation")
@ConditionalOnMissingBean
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public GraphQlSourceBuilderCustomizer sourceBuilderCustomizerWebmvc() {
public SentryInstrumentation sentryInstrumentationWebMvc(
final @NotNull ObjectProvider<SentryGraphqlInstrumentation.BeforeSpanCallback>
beforeSpanCallback) {
SentryIntegrationPackageStorage.getInstance().addIntegration("Spring5GrahQLWebMVC");
return sourceBuilderCustomizer(false);
return createInstrumentation(beforeSpanCallback, false);
}

@Bean
@Bean(name = "sentryInstrumentation")
@ConditionalOnMissingBean
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public GraphQlSourceBuilderCustomizer sourceBuilderCustomizerWebflux() {
public SentryInstrumentation sentryInstrumentationWebflux(
final @NotNull ObjectProvider<SentryGraphqlInstrumentation.BeforeSpanCallback>
beforeSpanCallback) {
SentryIntegrationPackageStorage.getInstance().addIntegration("Spring5GrahQLWebFlux");
return sourceBuilderCustomizer(true);
return createInstrumentation(beforeSpanCallback, true);
}

/**
* We're not setting defaultDataFetcherExceptionHandler here on purpose and instead use the
* resolver adapter below. This way Springs handler can still forward to other resolver adapters.
*/
private GraphQlSourceBuilderCustomizer sourceBuilderCustomizer(final boolean captureRequestBody) {
return (builder) ->
builder.configureGraphQl(
graphQlBuilder ->
graphQlBuilder.instrumentation(
new SentryInstrumentation(
null, new SentrySpringSubscriptionHandler(), captureRequestBody)));
private SentryInstrumentation createInstrumentation(
final @NotNull ObjectProvider<SentryGraphqlInstrumentation.BeforeSpanCallback>
beforeSpanCallback,
final boolean captureRequestBody) {
return new SentryInstrumentation(
beforeSpanCallback.getIfAvailable(),
new SentrySpringSubscriptionHandler(),
captureRequestBody);
}

@Bean
Expand Down

0 comments on commit 093ebc6

Please sign in to comment.