Open sgrove opened 7 years ago
Thanks for the input! Adding middleware seems like a generally useful feature. Getting the types right might be challenge. Can you elaborate on the types you would expect for "path to the resolver", "type of the parent resolver" and "resolver arguments"?
To expand on my previous comment...
The type of the function enter
(or exit
for that matter), will need to work for all types of fields. Since only the context type 'ctx
is identical for a query execution over a schema, this is the only part of a field which can easily be exposed to enter
. Loosely typed data can easily be exposed as well e.g. exposing the value of arguments as Yojson.Basic.json
. Exposing 'src
or 'args
is possible, but enter
will not be able to make any assumptions about their nature, so it will be hard to use for anything practical. Please share your use cases though, then I can more easily understand what you need.
@andreas: For context, I'm part of the Apollo team, and we've been working on a new design for exposing trace data to Apollo Optics. Currently, this relies on an agent running in your server that collects, aggregates, and batches up data to send to the Optics backend. In the new design, trace data for an individual request is exposed under extensions
as part of the GraphQL response, and a separate proxy process (provided by us, written in Go) is responsible for filtering out the trace data and performing the aggregation and batching. Our hope is that this will make it much easier to use Optics with every GraphQL server, not just with Node and Ruby (the only platforms for which we currently provide agents).
We're getting ready for early access at the moment, and we expect to make changes based on feedback, so the format is preliminary. But for an idea of what this looks like, see here. Happy to answer any questions you might have. Would be exciting to get support for instrumentation and the Apollo tracing format in OCaml!
@martijnwalraven: Thanks, that looks interesting. What does the startOffset
refer to? Do you have an example of a returned extensions
-value and how it's interpreted/visualized?
I plan on writing up a short spec for this soon, but startOffset
refers to the start time of a resolver call in nanoseconds, relative to the startTime
of the request.
One motivation for the format is to send data to Apollo Optics and visualize both individual traces and aggregated statistics there, but we would also like to add support to GraphiQL to show trace data for a single request.
To give an example of the format, for this query:
query {
hero {
name
friends {
name
}
}
}
The result would look like this:
{
"data": {
"hero": {
"name": "R2-D2",
"friends": [
{
"name": "Luke Skywalker"
},
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
}
]
}
},
"extensions": {
"tracing": {
"version": 1,
"startTime": "2017-07-24T14:03:16.008Z",
"endTime": "2017-07-24T14:03:16.009Z",
"duration": 1332446,
"execution": {
"resolvers": [
{
"path": [
"hero"
],
"parentType": "Query",
"fieldName": "hero",
"returnType": "Character",
"startOffset": 1108856,
"duration": 24201
},
{
"path": [
"hero",
"name"
],
"parentType": "Droid",
"fieldName": "name",
"returnType": "String!",
"startOffset": 1181364,
"duration": 7007
},
{
"path": [
"hero",
"friends"
],
"parentType": "Droid",
"fieldName": "friends",
"returnType": "[Character]",
"startOffset": 1196580,
"duration": 116086
},
{
"path": [
"hero",
"friends",
0,
"name"
],
"parentType": "Human",
"fieldName": "name",
"returnType": "String!",
"startOffset": 1284820,
"duration": 2516
},
{
"path": [
"hero",
"friends",
1,
"name"
],
"parentType": "Human",
"fieldName": "name",
"returnType": "String!",
"startOffset": 1297121,
"duration": 1373
},
{
"path": [
"hero",
"friends",
2,
"name"
],
"parentType": "Human",
"fieldName": "name",
"returnType": "String!",
"startOffset": 1305854,
"duration": 1286
}
]
}
}
}
}
As you can see, the overhead of the trace data is pretty significant, but it compresses quite well, so the recommendation is to enable gzip.
@andreas: Just a heads up that I just published a description of the proposed Apollo Tracing format. Would be great to get your feedback and see how we can add support for this to the OCaml server!
I'd like to have
enter
optional function argument to pass in on query execution that'll be called for each resolver with:Also, an
exit
optional function that would get the same as above, but also the return value of the resolverThis would let use collect telemetry on each resolver in a cross-cutting manner, and would be generally very useful.