Skip to content

Commit 22e43dc

Browse files
committed
feat(node): Add useOperationNameForRootSpan tographqlIntegration
1 parent d125ff2 commit 22e43dc

File tree

11 files changed

+322
-43
lines changed

11 files changed

+322
-43
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const { ApolloServer, gql } = require('apollo-server');
2+
3+
module.exports = () =>
4+
new ApolloServer({
5+
typeDefs: gql`type Query {
6+
hello: String
7+
world: String
8+
}
9+
type Mutation {
10+
login(email: String): String
11+
}`,
12+
resolvers: {
13+
Query: {
14+
hello: () => {
15+
return 'Hello!';
16+
},
17+
world: () => {
18+
return 'World!';
19+
},
20+
},
21+
Mutation: {
22+
login: async (_, { email }) => {
23+
return `${email}--token`;
24+
},
25+
},
26+
},
27+
introspection: false,
28+
debug: false,
29+
});

dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-mutation.js

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,36 +12,15 @@ Sentry.init({
1212
setInterval(() => {}, 1000);
1313

1414
async function run() {
15-
const { ApolloServer, gql } = require('apollo-server');
15+
const { gql } = require('apollo-server');
1616

1717
await Sentry.startSpan(
1818
{
1919
name: 'Test Transaction',
2020
op: 'transaction',
2121
},
2222
async span => {
23-
const server = new ApolloServer({
24-
typeDefs: gql`
25-
type Query {
26-
hello: String
27-
}
28-
type Mutation {
29-
login(email: String): String
30-
}
31-
`,
32-
resolvers: {
33-
Query: {
34-
hello: () => {
35-
return 'Hello world!';
36-
},
37-
},
38-
Mutation: {
39-
login: async (_, { email }) => {
40-
return `${email}--token`;
41-
},
42-
},
43-
},
44-
});
23+
const server = require('./apollo-server')();
4524

4625
// Ref: https://www.apollographql.com/docs/apollo-server/testing/testing/#testing-using-executeoperation
4726
await server.executeOperation({

dev-packages/node-integration-tests/suites/tracing/apollo-graphql/scenario-query.js

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,13 @@ Sentry.init({
1212
setInterval(() => {}, 1000);
1313

1414
async function run() {
15-
const { ApolloServer, gql } = require('apollo-server');
16-
1715
await Sentry.startSpan(
1816
{
1917
name: 'Test Transaction',
2018
op: 'transaction',
2119
},
2220
async span => {
23-
const typeDefs = gql`type Query { hello: String }`;
24-
25-
const resolvers = {
26-
Query: {
27-
hello: () => {
28-
return 'Hello world!';
29-
},
30-
},
31-
};
32-
33-
const server = new ApolloServer({
34-
typeDefs,
35-
resolvers,
36-
});
21+
const server = require('./apollo-server')();
3722

3823
// Ref: https://www.apollographql.com/docs/apollo-server/testing/testing/#testing-using-executeoperation
3924
await server.executeOperation({

dev-packages/node-integration-tests/suites/tracing/apollo-graphql/test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createRunner } from '../../../utils/runner';
22

33
describe('GraphQL/Apollo Tests', () => {
4-
test('CJS - should instrument GraphQL queries used from Apollo Server.', done => {
4+
test('should instrument GraphQL queries used from Apollo Server.', done => {
55
const EXPECTED_TRANSACTION = {
66
transaction: 'Test Transaction',
77
spans: expect.arrayContaining([
@@ -21,7 +21,7 @@ describe('GraphQL/Apollo Tests', () => {
2121
createRunner(__dirname, 'scenario-query.js').expect({ transaction: EXPECTED_TRANSACTION }).start(done);
2222
});
2323

24-
test('CJS - should instrument GraphQL mutations used from Apollo Server.', done => {
24+
test('should instrument GraphQL mutations used from Apollo Server.', done => {
2525
const EXPECTED_TRANSACTION = {
2626
transaction: 'Test Transaction',
2727
spans: expect.arrayContaining([
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const Sentry = require('@sentry/node');
2+
const { loggingTransport } = require('@sentry-internal/node-integration-tests');
3+
4+
const client = Sentry.init({
5+
dsn: 'https://[email protected]/1337',
6+
release: '1.0',
7+
tracesSampleRate: 1.0,
8+
integrations: [Sentry.graphqlIntegration({ useOperationNameForRootSpan: true })],
9+
transport: loggingTransport,
10+
});
11+
12+
const tracer = client.tracer;
13+
14+
// Stop the process from exiting before the transaction is sent
15+
setInterval(() => {}, 1000);
16+
17+
async function run() {
18+
await tracer.startActiveSpan('test span name', async span => {
19+
const server = require('../apollo-server')();
20+
21+
// Ref: https://www.apollographql.com/docs/apollo-server/testing/testing/#testing-using-executeoperation
22+
await server.executeOperation({
23+
query: 'query GetHello {hello}',
24+
});
25+
26+
setTimeout(() => {
27+
span.end();
28+
server.stop();
29+
}, 500);
30+
});
31+
}
32+
33+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
34+
run();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
const Sentry = require('@sentry/node');
2+
const { loggingTransport } = require('@sentry-internal/node-integration-tests');
3+
4+
const client = Sentry.init({
5+
dsn: 'https://[email protected]/1337',
6+
release: '1.0',
7+
tracesSampleRate: 1.0,
8+
integrations: [Sentry.graphqlIntegration({ useOperationNameForRootSpan: true })],
9+
transport: loggingTransport,
10+
});
11+
12+
const tracer = client.tracer;
13+
14+
// Stop the process from exiting before the transaction is sent
15+
setInterval(() => {}, 1000);
16+
17+
async function run() {
18+
const { gql } = require('apollo-server');
19+
20+
await tracer.startActiveSpan(
21+
'test span name',
22+
{
23+
kind: 1,
24+
attributes: { 'http.method': 'GET' },
25+
},
26+
async span => {
27+
const server = require('../apollo-server')();
28+
29+
// Ref: https://www.apollographql.com/docs/apollo-server/testing/testing/#testing-using-executeoperation
30+
await server.executeOperation({
31+
query: gql`mutation TestMutation($email: String){
32+
login(email: $email)
33+
}`,
34+
variables: { email: '[email protected]' },
35+
});
36+
37+
setTimeout(() => {
38+
span.end();
39+
server.stop();
40+
}, 500);
41+
},
42+
);
43+
}
44+
45+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
46+
run();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const Sentry = require('@sentry/node');
2+
const { loggingTransport } = require('@sentry-internal/node-integration-tests');
3+
4+
const client = Sentry.init({
5+
dsn: 'https://[email protected]/1337',
6+
release: '1.0',
7+
tracesSampleRate: 1.0,
8+
integrations: [Sentry.graphqlIntegration({ useOperationNameForRootSpan: true })],
9+
transport: loggingTransport,
10+
});
11+
12+
const tracer = client.tracer;
13+
14+
// Stop the process from exiting before the transaction is sent
15+
setInterval(() => {}, 1000);
16+
17+
async function run() {
18+
await tracer.startActiveSpan(
19+
'test span name',
20+
{
21+
kind: 1,
22+
attributes: { 'http.method': 'GET' },
23+
},
24+
async span => {
25+
const server = require('../apollo-server')();
26+
27+
// Ref: https://www.apollographql.com/docs/apollo-server/testing/testing/#testing-using-executeoperation
28+
await server.executeOperation({
29+
query: 'query {hello}',
30+
});
31+
32+
setTimeout(() => {
33+
span.end();
34+
server.stop();
35+
}, 500);
36+
},
37+
);
38+
}
39+
40+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
41+
run();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const Sentry = require('@sentry/node');
2+
const { loggingTransport } = require('@sentry-internal/node-integration-tests');
3+
4+
const client = Sentry.init({
5+
dsn: 'https://[email protected]/1337',
6+
release: '1.0',
7+
tracesSampleRate: 1.0,
8+
integrations: [Sentry.graphqlIntegration({ useOperationNameForRootSpan: true })],
9+
transport: loggingTransport,
10+
});
11+
12+
const tracer = client.tracer;
13+
14+
// Stop the process from exiting before the transaction is sent
15+
setInterval(() => {}, 1000);
16+
17+
async function run() {
18+
await tracer.startActiveSpan(
19+
'test span name',
20+
{
21+
kind: 1,
22+
attributes: { 'http.method': 'GET' },
23+
},
24+
async span => {
25+
const server = require('../apollo-server')();
26+
27+
// Ref: https://www.apollographql.com/docs/apollo-server/testing/testing/#testing-using-executeoperation
28+
await server.executeOperation({
29+
query: 'query GetHello {hello}',
30+
});
31+
32+
setTimeout(() => {
33+
span.end();
34+
server.stop();
35+
}, 500);
36+
},
37+
);
38+
}
39+
40+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
41+
run();
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { createRunner } from '../../../../utils/runner';
2+
3+
describe('GraphQL/Apollo Tests > useOperationNameForRootSpan', () => {
4+
test('useOperationNameForRootSpan works with single query operation', done => {
5+
const EXPECTED_TRANSACTION = {
6+
transaction: 'query GetHello',
7+
spans: expect.arrayContaining([
8+
expect.objectContaining({
9+
data: {
10+
'graphql.operation.name': 'GetHello',
11+
'graphql.operation.type': 'query',
12+
'graphql.source': 'query GetHello {hello}',
13+
'sentry.origin': 'auto.graphql.otel.graphql',
14+
},
15+
description: 'query GetHello',
16+
status: 'ok',
17+
origin: 'auto.graphql.otel.graphql',
18+
}),
19+
]),
20+
};
21+
22+
createRunner(__dirname, 'scenario-query.js').expect({ transaction: EXPECTED_TRANSACTION }).start(done);
23+
});
24+
25+
test('useOperationNameForRootSpan works with single mutation operation', done => {
26+
const EXPECTED_TRANSACTION = {
27+
transaction: 'mutation TestMutation',
28+
spans: expect.arrayContaining([
29+
expect.objectContaining({
30+
data: {
31+
'graphql.operation.name': 'TestMutation',
32+
'graphql.operation.type': 'mutation',
33+
'graphql.source': `mutation TestMutation($email: String) {
34+
login(email: $email)
35+
}`,
36+
'sentry.origin': 'auto.graphql.otel.graphql',
37+
},
38+
description: 'mutation TestMutation',
39+
status: 'ok',
40+
origin: 'auto.graphql.otel.graphql',
41+
}),
42+
]),
43+
};
44+
45+
createRunner(__dirname, 'scenario-mutation.js').expect({ transaction: EXPECTED_TRANSACTION }).start(done);
46+
});
47+
48+
test('useOperationNameForRootSpan ignores an invalid root span', done => {
49+
const EXPECTED_TRANSACTION = {
50+
transaction: 'test span name',
51+
spans: expect.arrayContaining([
52+
expect.objectContaining({
53+
data: {
54+
'graphql.operation.name': 'GetHello',
55+
'graphql.operation.type': 'query',
56+
'graphql.source': 'query GetHello {hello}',
57+
'sentry.origin': 'auto.graphql.otel.graphql',
58+
},
59+
description: 'query GetHello',
60+
status: 'ok',
61+
origin: 'auto.graphql.otel.graphql',
62+
}),
63+
]),
64+
};
65+
66+
createRunner(__dirname, 'scenario-invalid-root-span.js').expect({ transaction: EXPECTED_TRANSACTION }).start(done);
67+
});
68+
69+
test('useOperationNameForRootSpan works with single query operation without name', done => {
70+
const EXPECTED_TRANSACTION = {
71+
transaction: 'query',
72+
spans: expect.arrayContaining([
73+
expect.objectContaining({
74+
data: {
75+
'graphql.operation.type': 'query',
76+
'graphql.source': 'query {hello}',
77+
'sentry.origin': 'auto.graphql.otel.graphql',
78+
},
79+
description: 'query',
80+
status: 'ok',
81+
origin: 'auto.graphql.otel.graphql',
82+
}),
83+
]),
84+
};
85+
86+
createRunner(__dirname, 'scenario-no-operation-name.js').expect({ transaction: EXPECTED_TRANSACTION }).start(done);
87+
});
88+
});

0 commit comments

Comments
 (0)