-
Notifications
You must be signed in to change notification settings - Fork 633
Description
What version of OpenTelemetry are you using?
@opentelemetry/instrumentation-graphql: 0.56.0@opentelemetry/sdk-node: 0.208.0@opentelemetry/api: 1.9.0@opentelemetry/instrumentation-http: 0.208.0@opentelemetry/instrumentation-express: 0.57.0
What version of Node are you using?
Node.js 20.20.0
What did you do?
I set up OpenTelemetry with @opentelemetry/instrumentation-graphql in a NestJS application using
Apollo Server 5.
Environment:
@apollo/server: 5.1.0@nestjs/graphql: 13.2.0@nestjs/apollo: 13.2.1graphql: 16.12.0
Instrumentation setup (instrumentation.ts):
import { NodeSDK } from '@opentelemetry/sdk-node';
import { GraphQLInstrumentation } from '@opentelemetry/instrumentation-graphql';
// ... other imports
const sdk = new NodeSDK({
serviceName: 'hr-graphql-api',
traceExporter: new OTLPTraceExporter({
url: `${process.env.OTEL_EXPORTER_OTLP_ENDPOINT}/v1/traces`,
}),
instrumentations: [
new HttpInstrumentation(),
new ExpressInstrumentation(),
new GraphQLInstrumentation({}),
],
});
sdk.start(); Resolver definition:
@Resolver(() => Department)
export class DepartmentResolver {
@Query(() => Department, { name: 'department', nullable: true })
getById(@Args('id') id: string): Promise<Department | null> {
return this.departmentService.getById(id);
}
@ResolveField(() => Employees, { name: 'employees' })
listEmployees(
@Parent() department: Department,
@Args({ name: 'offset', type: () => Int, nullable: true }) offset = 0,
@Args({ name: 'limit', type: () => Int, nullable: true }) limit = 10,
): Promise<Employees> {
return this.employeeService.listByDepartmentId(department.id, offset, limit);
}
} GraphQL query executed:
query getDepartment {
department(id: "d009") {
id
name
employees {
items {
id
lastName
firstName
}
}
}
} Reproduction repository:
https://github.com/lidigobeyond/graphql-otel-in-action
Steps to reproduce:
- Clone the repository
git clone --recurse-submodules https://github.com/lidigobeyond/graphql-otel-in-action.git
cd graphql-otel-in-action
- Start the application with Docker Compose
docker-compose up --build
Note: Initial database setup may take 1-2 minutes.
- Open GraphQL Playground at http://localhost:3000/api/graphql
- Execute the following query:
query getDepartment {
department(id: "d009") {
id
name
employees {
items {
id
lastName
firstName
}
}
}
} - Open Jaeger UI at http://localhost:16686 and inspect the trace
What did you expect to see?
I expected to see spans for:
- graphql.resolve department - the root Query resolver (getById method)
- graphql.resolve department.employees - the ResolveField resolver (listEmployees method)
Expected span hierarchy:
POST /api/graphql
└── query getDepartment
├── graphql.resolve department <-- Expected but missing
├── graphql.resolve department.id
├── graphql.resolve department.name
└── graphql.resolve department.employees <-- Expected but missing
└── graphql.resolve department.employees.items
What did you see instead?
Custom resolvers decorated with @query and @ResolveField do not generate spans.
Only trivial scalar field resolvers (id, name, firstName, lastName) generate spans.
Actual span hierarchy:
POST /api/graphql
└── query department
├── graphql.resolve department.id <-- Only scalar fields have spans
├── graphql.resolve department.name
└── graphql.resolve department.employees.items
├── graphql.resolve department.employees.items..id
├── graphql.resolve department.employees.items..lastName
└── graphql.resolve department.employees.items.*.firstName
The graphql.resolve department and graphql.resolve department.employees spans are completely
missing.
Tip:
https://github.blog/news-insights/product-news/add-reactions-to-pull-requests-issues-and-comments/
with 👍 to help prioritize this issue. Please use comments to provide useful context, avoiding +1
or me too, to help us triage it.
https://opentelemetry.io/community/end-user/issue-participation/.