Exposing trace data for your GraphQL server with Apollo Tracing
Martijn Walraven
Today I’m excited to introduce you to Apollo Tracing, a GraphQL extension for performance monitoring that we’ve been working on for the last few months. Thanks to the community, Apollo Tracing already works with most popular GraphQL server libraries, including Node, Ruby, Scala, Java, and Elixir, and it enables you to easily get resolver-level performance information as part of a GraphQL response.
Apollo Tracing works by including data in the extensions
field of the GraphQL response, which is reserved by the GraphQL spec for extra information that a server wants to return. That way, you have access to performance traces alongside the data returned by your query. It’s already supported by Apollo Engine, the new version of Optics that entered preview recently, and we’re excited to see what other kinds of integrations people can build on top of this format. For example, you could create a panel in GraphiQL that visualizes trace data on a per-response basis.
We’d like to thank Oleg Ilyenko for adding support for Apollo Tracing to Sangria, Reginald Suh from Universe for the Ruby support, Brad Baker from Atlassian for Java, and Sikan He for Elixir.
Example response
Here’s an example of a response with trace data included:
{
"data": {
"hero": {
"name": "Luke Skywalker",
"friends": [
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
},
{
"name": "C-3PO"
},
{
"name": "R2-D2"
}
]
}
},
"extensions": {
"tracing": {
"version": 1,
"startTime": "2017-10-16T18:58:06.797Z",
"endTime": "2017-10-16T18:58:06.811Z",
"duration": 13962507,
"execution": {
"resolvers": [
{
"path": [
"hero"
],
"parentType": "Query",
"fieldName": "hero",
"returnType": "Character",
"startOffset": 11089188,
"duration": 181335
},
{
"path": [
"hero",
"name"
],
"parentType": "Human",
"fieldName": "name",
"returnType": "String!",
"startOffset": 12304767,
"duration": 103632
},
{
"path": [
"hero",
"friends"
],
"parentType": "Human",
"fieldName": "friends",
"returnType": "[Character]",
"startOffset": 12588394,
"duration": 1106042
},
{
"path": [
"hero",
"friends",
0,
"name"
],
"parentType": "Human",
"fieldName": "name",
"returnType": "String!",
"startOffset": 13583004,
"duration": 16006
},
...,
{
"path": [
"hero",
"friends",
2,
"name"
],
"parentType": "Droid",
"fieldName": "name",
"returnType": "String!",
"startOffset": 13662093,
"duration": 1928
},
...
]
}
}
}
}
As you can see, the trace data includes the start and end time of the request, as well as detailed timings and type information for individual resolvers. Resolver-level data is organized by path, similar to the way error paths are handled in the GraphQL spec. The reason for including the type information is that we didn’t want interpretation of the results to require knowledge of the schema, especially because schemas may change, and because some resolvers depend on runtime type information.
For a more detailed description of the format, see the <a href="https://github.com/apollographql/apollo-tracing" target="_blank" rel="noreferrer noopener">apollo-tracing</a>
repo.
Try it today
If you’re using Apollo Server, support for Apollo Tracing is built-in and you can try it out just by setting tracing
to true
:
app.use('/graphql', bodyParser.json(), graphqlExpress({ schema, context: {}, tracing: true, }));
Since options passed to graphqlExpress
can be a function, you can turn tracing on and off on a per-request basis.
Supported GraphQL servers
For other servers, you can follow these instructions to enable tracing:
Supporting more servers and tools
We think this format is broadly useful, and we’d love to work with you to add support for it to your tools of choice. If you’re looking for a first idea, we especially think it would be great to see support for Apollo Tracing in GraphiQL and the Apollo Client developer tools!
If you’re interested in working on support for other GraphQL servers, or integrations with more tools, please get in touch on the #apollo-tracing
channel on the Apollo Slack.