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://public@dsn.ingest.sentry.io/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', () => {
55
55
. start ( )
56
56
. completed ( ) ;
57
57
} ) ;
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
+ } ) ;
58
83
} ) ;
Original file line number Diff line number Diff line change 1
1
import type { AttributeValue } from '@opentelemetry/api' ;
2
+ import { SpanStatusCode } from '@opentelemetry/api' ;
2
3
import { GraphQLInstrumentation } from '@opentelemetry/instrumentation-graphql' ;
3
4
import type { IntegrationFn } from '@sentry/core' ;
4
5
import { defineIntegration , getRootSpan , spanToJSON } from '@sentry/core' ;
@@ -45,9 +46,16 @@ export const instrumentGraphql = generateInstrumentOnce(
45
46
46
47
return {
47
48
...options ,
48
- responseHook ( span ) {
49
+ responseHook ( span , result ) {
49
50
addOriginToSpan ( span , 'auto.graphql.otel.graphql' ) ;
50
51
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
+
51
59
const attributes = spanToJSON ( span ) . data ;
52
60
53
61
// 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