-
Notifications
You must be signed in to change notification settings - Fork 457
feat(graphql): add graphql-core integration #3647
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
6eb3d42
to
5446941
Compare
b90e8a1
to
3dd8cbe
Compare
assert len(spans) == 1 | ||
assert spans[0].name == "graphql" | ||
assert spans[0].resource == test_source | ||
assert spans[0].service == "graphql" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I plan to increase test coverage if this general approach looks good. I'll also add a sample django-graphene app with snapshot tests
6c81d91
to
c7bb795
Compare
b10f07d
to
35b530c
Compare
bb2cfeb
to
16dfc0f
Compare
I'm very excited for this change. Will instrumentation of all GraphQL APIs come free with using |
tests/snapshots/tests.contrib.graphql.test_graphql.test_graphql_error.json
Show resolved
Hide resolved
a75bffd
to
1c27a34
Compare
tests/snapshots/tests.contrib.graphql.test_graphql.test_graphql_error_v2_promise.json
Outdated
Show resolved
Hide resolved
5ed26c5
to
209d645
Compare
Hi @EtienneLamoureux, thanks for reaching out. The current plan is to instrument all resolvers using Would you like to test out a POC of this integration and let us know what you think? We'd greatly appreciate any feedback. |
Hi @mabdinur, Manually tagging my resolvers is perfectly acceptable for my use-case, no problem. And I'd gladly test a POC of this feature! What's the best way to get a hold of a build with it in it? |
Hey @EtienneLamoureux, sorry about the delay. Here's a link to our public slack channel: https://chat.datadoghq.com/. Feel free to join and we can continue our conversation there. Thanks again helping us test the graphql integration 😊 |
8e08f26
to
e316295
Compare
409211d
to
6476619
Compare
ddtrace/contrib/graphql/patch.py
Outdated
_w("graphql", "execute_sync", _traced_operation("graphql.execute")) | ||
_w("graphql.execution", "execute_sync", _traced_operation("graphql.execute")) | ||
|
||
# patch all resolvers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of monkey patching resolve_field
I could instead pass a trace middleware to graphql.execute()
. This middleware would wrap resolvers in a span when ExecutionContext.resolve_field is called. Both approaches produce equivalent instrumentation. Although using a trace middleware could provide more accurate span durations it comes with some performance costs. We will need to iterated over existing middleware and apply the TracedResolverMiddleware
everytime graphql.execute
is called. I think the current monkey patching approach is easier to follow.
ex:
import graphql
class TracedResolverMiddleware(object):
def resolve(self, next, root, info, **args):
pin = Pin.get_from(graphql)
if not pin or not pin.enabled():
return next(root, info, **args)
with pin.tracer.trace(
name="graphql.resolve",
resource=info.field_name,
service=trace_utils.int_service(pin, config.graphql),
span_type=SpanTypes.WEB,
) as span:
_init_span(span)
return next(root, info, **args)
# wraps all resolvers in the schema
result = graphql.execute(schema, source, middleware=[TracedResolverMiddleware()])
6476619
to
5a372b6
Compare
5a372b6
to
b0304a8
Compare
The graphql integration will be introduced in the following PR: #3878 |
Graphql-core Integration
Overview
This integration supports graphql-core 3 and graphql-core 2. By transitive dependencies executing graphql schemas in
graphene>2.0
is also supported. This integration provides instrumentation for executing graphql queries usinggraphql.graphql()
,graphql.graphql_sync()
,graphql.execute()
, andgraphql.execution.execute()
,graphql.execution.executor.execute()
,graphql.execute_sync()
, andgraphql.execution.execute_sync()
.Resolves #925.
Implementation Details
graphql-core this integration provides support for parsing, building, validating, and executing graphql schemas. It also provides additional insight into resolving GraphQLFields.
The methods listed below are the main parts of the public api which are fully supported by the ddtrace library. All other methods listed in graphql.init will not produce any instrumentation.
graphql.graphql() and graphql.graphql_sync()
When graphql.graphql() or graphql.graphql_sync (in
graphql-core>=3
) is called the following trace is produced:converts the body of an incoming graphql request into a graphql document
ensures a graphql schema is syntactically correct and can be executed in a given context
executes a valid graphql schema and returns a response
Graphql queries can be complex and often resolve multiple Graphql fields in single request. Instrumenting resolvers provides insight on the execution of individual graphql fields and can highlight bottlenecks in fetching specific types of data. However for some applications this can produce a large number of spans.
Note: If a GraphqlError is raised while parsing or validating a graphql query then
graphql.execute
will not be called and instrumented. For this reason we add the graphql source string to the graphql.query span AND the graphql.execute span.graphql.execute() and graphql.execution.execute()
When
execute()
is called the following trace is produced:Note:
graphql-core>=3.1
introducedexecute_sync
. Usinggraphql.execute_sync()
andgraphql.execution.execute_sync()
should produce the same trace asgraphql.execute()
.Future Work
graphql.source
,graphql.operation.type
andgraphql.operation.name
span tags to maintain feature parity with the .NET tracer.graphql.execution.executor.execute()
in graphql-core 2 this version of the library generates graphql.execute and graphql.resolver spans when subscriptions are executed. For consistency we should extend this functionality to graphql-core 3 and offically support graphql subscriptions.Checklist