Skip to content

Commit

Permalink
feat(node): Add useOperationNameForRootSpan tographqlIntegration (#…
Browse files Browse the repository at this point in the history
…13248)

This introduces a new option for the `graphqlIntegration`,
`useOperationNameForRootSpan`, which is by default `true` but can be
disabled in integration settings like this: `Sentry.graphqlIntegration({
useOperationNameForRootSpan: true })`.

With this setting enabled, the graphql instrumentation will update the
`http.server` root span it is in (if there is one) will be appended to
the span name. So instead of having all root spans be `POST /graphql`,
the names will now be e.g. `POST /graphql (query MyQuery)`.

If there are multiple operations in a single http request, they will be
appended like `POST /graphql (query Query1, query Query2)`, up to a
limit of 5, at which point they will be appended as `+2` or similar.

Closes #13238
  • Loading branch information
mydea committed Aug 8, 2024
1 parent b17ac59 commit 0ca8821
Show file tree
Hide file tree
Showing 17 changed files with 536 additions and 51 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const { ApolloServer, gql } = require('apollo-server');
const Sentry = require('@sentry/node');

module.exports = () => {
return Sentry.startSpan({ name: 'Test Server Start' }, () => {
return new ApolloServer({
typeDefs: gql`type Query {
hello: String
world: String
}
type Mutation {
login(email: String): String
}`,
resolvers: {
Query: {
hello: () => {
return 'Hello!';
},
world: () => {
return 'World!';
},
},
Mutation: {
login: async (_, { email }) => {
return `${email}--token`;
},
},
},
introspection: false,
debug: false,
});
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,15 @@ Sentry.init({
setInterval(() => {}, 1000);

async function run() {
const { ApolloServer, gql } = require('apollo-server');
const { gql } = require('apollo-server');
const server = require('./apollo-server')();

await Sentry.startSpan(
{
name: 'Test Transaction',
op: 'transaction',
},
async span => {
const server = new ApolloServer({
typeDefs: gql`
type Query {
hello: String
}
type Mutation {
login(email: String): String
}
`,
resolvers: {
Query: {
hello: () => {
return 'Hello world!';
},
},
Mutation: {
login: async (_, { email }) => {
return `${email}--token`;
},
},
},
});

// Ref: https://www.apollographql.com/docs/apollo-server/testing/testing/#testing-using-executeoperation
await server.executeOperation({
query: gql`mutation Mutation($email: String){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,14 @@ Sentry.init({
setInterval(() => {}, 1000);

async function run() {
const { ApolloServer, gql } = require('apollo-server');
const server = require('./apollo-server')();

await Sentry.startSpan(
{
name: 'Test Transaction',
op: 'transaction',
},
async span => {
const typeDefs = gql`type Query { hello: String }`;

const resolvers = {
Query: {
hello: () => {
return 'Hello world!';
},
},
};

const server = new ApolloServer({
typeDefs,
resolvers,
});

// Ref: https://www.apollographql.com/docs/apollo-server/testing/testing/#testing-using-executeoperation
await server.executeOperation({
query: '{hello}',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { createRunner } from '../../../utils/runner';

// Graphql Instrumentation emits some spans by default on server start
const EXPECTED_START_SERVER_TRANSACTION = {
transaction: 'Test Server Start',
};

describe('GraphQL/Apollo Tests', () => {
test('CJS - should instrument GraphQL queries used from Apollo Server.', done => {
test('should instrument GraphQL queries used from Apollo Server.', done => {
const EXPECTED_TRANSACTION = {
transaction: 'Test Transaction',
spans: expect.arrayContaining([
Expand All @@ -18,10 +23,13 @@ describe('GraphQL/Apollo Tests', () => {
]),
};

createRunner(__dirname, 'scenario-query.js').expect({ transaction: EXPECTED_TRANSACTION }).start(done);
createRunner(__dirname, 'scenario-query.js')
.expect({ transaction: EXPECTED_START_SERVER_TRANSACTION })
.expect({ transaction: EXPECTED_TRANSACTION })
.start(done);
});

test('CJS - should instrument GraphQL mutations used from Apollo Server.', done => {
test('should instrument GraphQL mutations used from Apollo Server.', done => {
const EXPECTED_TRANSACTION = {
transaction: 'Test Transaction',
spans: expect.arrayContaining([
Expand All @@ -39,6 +47,9 @@ describe('GraphQL/Apollo Tests', () => {
]),
};

createRunner(__dirname, 'scenario-mutation.js').expect({ transaction: EXPECTED_TRANSACTION }).start(done);
createRunner(__dirname, 'scenario-mutation.js')
.expect({ transaction: EXPECTED_START_SERVER_TRANSACTION })
.expect({ transaction: EXPECTED_TRANSACTION })
.start(done);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const Sentry = require('@sentry/node');
const { loggingTransport } = require('@sentry-internal/node-integration-tests');

const client = Sentry.init({
dsn: 'https://[email protected]/1337',
release: '1.0',
tracesSampleRate: 1.0,
integrations: [Sentry.graphqlIntegration({ useOperationNameForRootSpan: true })],
transport: loggingTransport,
});

const tracer = client.tracer;

// Stop the process from exiting before the transaction is sent
setInterval(() => {}, 1000);

async function run() {
const server = require('../apollo-server')();

await tracer.startActiveSpan('test span name', async span => {
// Ref: https://www.apollographql.com/docs/apollo-server/testing/testing/#testing-using-executeoperation
await server.executeOperation({
query: 'query GetHello {hello}',
});

setTimeout(() => {
span.end();
server.stop();
}, 500);
});
}

// eslint-disable-next-line @typescript-eslint/no-floating-promises
run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const Sentry = require('@sentry/node');
const { loggingTransport } = require('@sentry-internal/node-integration-tests');

const client = Sentry.init({
dsn: 'https://[email protected]/1337',
release: '1.0',
tracesSampleRate: 1.0,
integrations: [Sentry.graphqlIntegration({ useOperationNameForRootSpan: true })],
transport: loggingTransport,
});

const tracer = client.tracer;

// Stop the process from exiting before the transaction is sent
setInterval(() => {}, 1000);

async function run() {
const server = require('../apollo-server')();

await tracer.startActiveSpan(
'test span name',
{
kind: 1,
attributes: { 'http.method': 'GET', 'http.route': '/test-graphql' },
},
async span => {
for (let i = 1; i < 10; i++) {
// Ref: https://www.apollographql.com/docs/apollo-server/testing/testing/#testing-using-executeoperation
await server.executeOperation({
query: `query GetHello${i} {hello}`,
});
}

setTimeout(() => {
span.end();
server.stop();
}, 500);
},
);
}

// eslint-disable-next-line @typescript-eslint/no-floating-promises
run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const Sentry = require('@sentry/node');
const { loggingTransport } = require('@sentry-internal/node-integration-tests');

const client = Sentry.init({
dsn: 'https://[email protected]/1337',
release: '1.0',
tracesSampleRate: 1.0,
integrations: [Sentry.graphqlIntegration({ useOperationNameForRootSpan: true })],
transport: loggingTransport,
});

const tracer = client.tracer;

// Stop the process from exiting before the transaction is sent
setInterval(() => {}, 1000);

async function run() {
const server = require('../apollo-server')();

await tracer.startActiveSpan(
'test span name',
{
kind: 1,
attributes: { 'http.method': 'GET', 'http.route': '/test-graphql' },
},
async span => {
// Ref: https://www.apollographql.com/docs/apollo-server/testing/testing/#testing-using-executeoperation
await server.executeOperation({
query: 'query GetWorld {world}',
});

await server.executeOperation({
query: 'query GetHello {hello}',
});

setTimeout(() => {
span.end();
server.stop();
}, 500);
},
);
}

// eslint-disable-next-line @typescript-eslint/no-floating-promises
run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const Sentry = require('@sentry/node');
const { loggingTransport } = require('@sentry-internal/node-integration-tests');

const client = Sentry.init({
dsn: 'https://[email protected]/1337',
release: '1.0',
tracesSampleRate: 1.0,
integrations: [Sentry.graphqlIntegration({ useOperationNameForRootSpan: true })],
transport: loggingTransport,
});

const tracer = client.tracer;

// Stop the process from exiting before the transaction is sent
setInterval(() => {}, 1000);

async function run() {
const { gql } = require('apollo-server');
const server = require('../apollo-server')();

await tracer.startActiveSpan(
'test span name',
{
kind: 1,
attributes: { 'http.method': 'GET', 'http.route': '/test-graphql' },
},
async span => {
// Ref: https://www.apollographql.com/docs/apollo-server/testing/testing/#testing-using-executeoperation
await server.executeOperation({
query: gql`mutation TestMutation($email: String){
login(email: $email)
}`,
variables: { email: '[email protected]' },
});

setTimeout(() => {
span.end();
server.stop();
}, 500);
},
);
}

// eslint-disable-next-line @typescript-eslint/no-floating-promises
run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const Sentry = require('@sentry/node');
const { loggingTransport } = require('@sentry-internal/node-integration-tests');

const client = Sentry.init({
dsn: 'https://[email protected]/1337',
release: '1.0',
tracesSampleRate: 1.0,
integrations: [Sentry.graphqlIntegration({ useOperationNameForRootSpan: true })],
transport: loggingTransport,
});

const tracer = client.tracer;

// Stop the process from exiting before the transaction is sent
setInterval(() => {}, 1000);

async function run() {
const server = require('../apollo-server')();

await tracer.startActiveSpan(
'test span name',
{
kind: 1,
attributes: { 'http.method': 'GET', 'http.route': '/test-graphql' },
},
async span => {
// Ref: https://www.apollographql.com/docs/apollo-server/testing/testing/#testing-using-executeoperation
await server.executeOperation({
query: 'query {hello}',
});

setTimeout(() => {
span.end();
server.stop();
}, 500);
},
);
}

// eslint-disable-next-line @typescript-eslint/no-floating-promises
run();
Loading

0 comments on commit 0ca8821

Please sign in to comment.