Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Add graphql-java instrumentation. #1777

Merged
merged 25 commits into from
Nov 8, 2021
Merged

Feat: Add graphql-java instrumentation. #1777

merged 25 commits into from
Nov 8, 2021

Conversation

maciejwalkowiak
Copy link
Contributor

@maciejwalkowiak maciejwalkowiak commented Oct 22, 2021

📜 Description

Add graphql-java instrumentation.

  • exception handler - SentryDataFetcherExceptionHandler reports exception to Sentry and invokes a delegate

Sample usage with Netflix DGS:

@Bean
SentryDataFetcherExceptionHandler sentryDataFetcherExceptionHandler() {
  // delegate to default Netflix DGS exception handler
  return new SentryDataFetcherExceptionHandler(new DefaultDataFetcherExceptionHandler());
}
  • tracing - SentryInstrumentation creates spans around data fetchers. Since there can be more than a single query executed within a single HTTP request, the transaction name is POST /graphql and resolving each query/field is reported as separate span.

It is advised to turn on sentry.max-request-body-size reporting, to get a complete GraphQL query in request parameters.

image

💡 Motivation and Context

Fixes #1755

Both Netflix DGS and Spring GraphQL are based on graphql-java. Changes introduced in this PR will work for both solutions as well as using graphql-java directly.

💚 How did you test it?

Unit tests.

📝 Checklist

  • I reviewed the submitted code
  • I added tests to verify the changes
  • I updated the docs if needed
  • No breaking changes

🔮 Next steps

  • Add error handler
  • Create sample project

Optionally, once Spring GraphQL project reaches GA, add corresponding sample.

@codecov-commenter
Copy link

codecov-commenter commented Oct 22, 2021

Codecov Report

Merging #1777 (8ec6a1f) into main (2d8a74a) will decrease coverage by 0.02%.
The diff coverage is 72.72%.

Impacted file tree graph

@@             Coverage Diff              @@
##               main    #1777      +/-   ##
============================================
- Coverage     75.75%   75.73%   -0.03%     
- Complexity     2180     2193      +13     
============================================
  Files           216      218       +2     
  Lines          7739     7794      +55     
  Branches        824      828       +4     
============================================
+ Hits           5863     5903      +40     
- Misses         1476     1488      +12     
- Partials        400      403       +3     
Impacted Files Coverage Δ
.../java/io/sentry/graphql/SentryInstrumentation.java 72.34% <72.34%> (ø)
...try/graphql/SentryDataFetcherExceptionHandler.java 75.00% <75.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2d8a74a...8ec6a1f. Read the comment docs.

@maciejwalkowiak maciejwalkowiak marked this pull request as ready for review October 25, 2021 09:53
@@ -0,0 +1,36 @@
package io.sentry.graphql.java;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to have the .java in the name?

Copy link
Contributor

@marandaneto marandaneto Nov 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still called sentry-graphql-java, should we rename it to sentry-graphql? we only add the android suffix to Android modules

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the library we integrate with is called graphql-java - i do think it should stay as the module name.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bruno-garcia are u fine with it? I recall you didn't want to add such sufixes

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it must match in all cases the package name. The proposal from manoel sounds better to me unless folks have strong options not to take that route

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with or without fine with me, I'd rather keep it without -java if I'd have to vote.
@romtsn ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same maybe call it sentry-graphql-server? :D fine with everything

@maciejwalkowiak
Copy link
Contributor Author

Few improvements to instrumentation:

  • do not finish parent span
  • handle exceptions thrown by data fetchers
  • set parent span status if any of child spans fails

So now, if any of the child spans fails - meaning that there are errors present in GraphQL response, we set the parent span status - which in most cases will be a transaction - to INTERNAL_ERROR.

@marandaneto
Copy link
Contributor

missing the craft configuration, release-registry and docs later on :)

the module name is still with -java

@marandaneto
Copy link
Contributor

let's discuss https://github.com/getsentry/sentry-java/pull/1777/files#r742653695 today and approve/merge, nothing but this comment blocks me to approve, merge and release, thanks for doing this @maciejwalkowiak

@romtsn wanna have a look?

Copy link
Contributor

@marandaneto marandaneto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment on lines +66 to +67
final ISpan transaction = tracingState.getTransaction();
if (transaction != null) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to use the SentryInstrumentation in our spring-graphql application (using Spring Boot), but the transaction here is always null. Is it necessary to manually start a transaction? Or how can I get this to work?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see the Docs PR getsentry/sentry-docs#4385

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I didn't see that PR yet. But unfortunately it doesn't solve the issue; performance tracing is set up, but apparently a transaction isn't started before graphql execution.

For now I think I've mitigated it by adding a WebInterceptor (a spring-graphql concept), that starts a transaction;

class SentryWebInterceptor : WebInterceptor {
    override fun intercept(webInput: WebInput, chain: WebInterceptorChain): Mono<WebOutput> {
        val span = Sentry.getSpan() ?: Sentry.startTransaction("GraphQL", webInput.operationName ?: "none", true)

        return chain.next(webInput).doFinally {
            span.finish()
        }
    }
}

According to the PR description "the transaction name is POST /graphql", but this doesn't seem to be defined explicitly, so could it be that the assumption is made that the the http/network layer already starts the transaction, but that somehow with spring-graphql this doesn't happen?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the graphql integration only creates spans if there's an active transaction, so ideally you'd use it along with an integration that has the ability to create a transaction, eg https://docs.sentry.io/platforms/java/guides/spring-boot/performance/instrumentation/automatic-instrumentation/
or just create a transaction yourself

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just found that out too, but unfortunately there's no auto instrumentation available for applications using webflux, so I guess I have to implement what's in SentryTracingFilter, but then reactive.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, #1807
no priorities for now, but if you feel adding support via PR, happy to guide :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

GraphQL integration for server side
6 participants