File tree Expand file tree Collapse file tree 3 files changed +77
-1
lines changed
dev-packages/node-integration-tests/suites/tracing/apollo-graphql
packages/node/src/integrations/tracing Expand file tree Collapse file tree 3 files changed +77
-1
lines changed Original file line number Diff line number Diff line change 1+ const Sentry = require ( '@sentry/node' ) ;
2+ const { loggingTransport } = require ( '@sentry-internal/node-integration-tests' ) ;
3+
4+ Sentry . init ( {
5+ dsn :
'https://[email protected] /1337' , 6+ release : '1.0' ,
7+ tracesSampleRate : 1.0 ,
8+ transport : loggingTransport ,
9+ } ) ;
10+
11+ // Stop the process from exiting before the transaction is sent
12+ setInterval ( ( ) => { } , 1000 ) ;
13+
14+ async function run ( ) {
15+ const { gql } = require ( 'apollo-server' ) ;
16+ const server = require ( './apollo-server' ) ( ) ;
17+
18+ await Sentry . startSpan (
19+ {
20+ name : 'Test Transaction' ,
21+ op : 'transaction' ,
22+ } ,
23+ async span => {
24+ // Ref: https://www.apollographql.com/docs/apollo-server/testing/testing/#testing-using-executeoperation
25+ await server . executeOperation ( {
26+ query : gql `
27+ mutation Mutation($email: String) {
28+ login(email: $email)
29+ }
30+ ` ,
31+ // We want to trigger an error by passing an invalid variable type
32+ variables : { email : 123 } ,
33+ } ) ;
34+
35+ setTimeout ( ( ) => {
36+ span . end ( ) ;
37+ server . stop ( ) ;
38+ } , 500 ) ;
39+ } ,
40+ ) ;
41+ }
42+
43+ run ( ) ;
Original file line number Diff line number Diff line change @@ -55,4 +55,29 @@ describe('GraphQL/Apollo Tests', () => {
5555 . start ( )
5656 . completed ( ) ;
5757 } ) ;
58+
59+ test ( 'should handle GraphQL errors.' , async ( ) => {
60+ const EXPECTED_TRANSACTION = {
61+ transaction : 'Test Transaction (mutation Mutation)' ,
62+ spans : expect . arrayContaining ( [
63+ expect . objectContaining ( {
64+ data : {
65+ 'graphql.operation.name' : 'Mutation' ,
66+ 'graphql.operation.type' : 'mutation' ,
67+ 'graphql.source' : 'mutation Mutation($email: String) {\n login(email: $email)\n}' ,
68+ 'sentry.origin' : 'auto.graphql.otel.graphql' ,
69+ } ,
70+ description : 'mutation Mutation' ,
71+ status : 'unknown_error' ,
72+ origin : 'auto.graphql.otel.graphql' ,
73+ } ) ,
74+ ] ) ,
75+ } ;
76+
77+ await createRunner ( __dirname , 'scenario-error.js' )
78+ . expect ( { transaction : EXPECTED_START_SERVER_TRANSACTION } )
79+ . expect ( { transaction : EXPECTED_TRANSACTION } )
80+ . start ( )
81+ . completed ( ) ;
82+ } ) ;
5883} ) ;
Original file line number Diff line number Diff line change 11import type { AttributeValue } from '@opentelemetry/api' ;
2+ import { SpanStatusCode } from '@opentelemetry/api' ;
23import { GraphQLInstrumentation } from '@opentelemetry/instrumentation-graphql' ;
34import type { IntegrationFn } from '@sentry/core' ;
45import { defineIntegration , getRootSpan , spanToJSON } from '@sentry/core' ;
@@ -45,9 +46,16 @@ export const instrumentGraphql = generateInstrumentOnce(
4546
4647 return {
4748 ...options ,
48- responseHook ( span ) {
49+ responseHook ( span , result ) {
4950 addOriginToSpan ( span , 'auto.graphql.otel.graphql' ) ;
5051
52+ // We want to ensure spans are marked as errored if there are errors in the result
53+ // We only do that if the span is not already marked with a status
54+ const resultWithMaybeError = result as { errors ?: { message : string } [ ] } ;
55+ if ( resultWithMaybeError . errors ?. length && ! spanToJSON ( span ) . status ) {
56+ span . setStatus ( { code : SpanStatusCode . ERROR } ) ;
57+ }
58+
5159 const attributes = spanToJSON ( span ) . data ;
5260
5361 // If operation.name is not set, we fall back to use operation.type only
You can’t perform that action at this time.
0 commit comments