Summary
The UnifiedTrace module for GraphQL does not call Contrib::Analytics.set_measured(span) on the graphql.execute span, which prevents RED (Rate, Errors, Duration) metrics from being generated. This makes it impossible to use standard Datadog monitoring features like the Service Page operations list and trace.graphql.* metrics.
Expected Behavior
When using with_unified_tracer: true, the graphql.execute span should:
- Appear as a top-level operation in the Datadog Service Page
- Generate
trace.graphql.execute.* metrics (hits, errors, duration)
- Be usable for monitors and SLOs based on these metrics
Actual Behavior
- The
graphql.execute span appears correctly in traces with proper resource names
- However, it does not appear in the Service Page operations list
- No
trace.graphql.* metrics are generated
- Cannot create monitors/SLOs based on GraphQL operation performance
Root Cause Analysis
Comparing UnifiedTrace with other integrations that correctly appear as top-level operations:
Sidekiq ServerTracer (source):
span.set_tag(
Datadog::Tracing::Metadata::Ext::TAG_KIND,
Datadog::Tracing::Metadata::Ext::SpanKind::TAG_CONSUMER
)
# Measure service stats
Contrib::Analytics.set_measured(span) # ✅ Present
Rack Middleware (source):
request_span.set_tag(Tracing::Metadata::Ext::TAG_KIND, Tracing::Metadata::Ext::SpanKind::TAG_SERVER)
# Measure service stats
Contrib::Analytics.set_measured(request_span) # ✅ Present
GraphQL UnifiedTrace (source):
# In execute_query method:
span.set_tag(Tracing::Metadata::Ext::TAG_KIND, Tracing::Metadata::Ext::SpanKind::TAG_SERVER)
# ❌ Missing: Contrib::Analytics.set_measured(span)
The comment on line 86-87 states:
# Ensure this span can be aggregated by in the Datadog App, and generates RED metrics.
span.set_tag(Tracing::Metadata::Ext::TAG_KIND, Tracing::Metadata::Ext::SpanKind::TAG_SERVER)
However, setting TAG_KIND = TAG_SERVER alone is not sufficient to generate RED metrics. The _dd.measured = 1 tag (set by set_measured()) is required.
Suggested Fix
In unified_trace.rb, add the set_measured() call in the execute_query method's before lambda:
def execute_query(*args, query:, **kwargs)
trace(
proc { super },
'execute',
operation_resource(query.selected_operation),
lambda { |span|
span.set_tag(Tracing::Metadata::Ext::TAG_KIND, Tracing::Metadata::Ext::SpanKind::TAG_SERVER)
# Add this line to enable RED metrics generation
Contrib::Analytics.set_measured(span)
span.set_tag('graphql.source', query.query_string)
# ... rest of the method
},
# ...
)
end
Environment
- dd-trace-rb version: 2.x (tested with latest)
- Ruby version: 3.2.2
- GraphQL version: 2.x
- Configuration:
Datadog.configure do |c|
c.tracing.instrument :graphql, with_unified_tracer: true
end
Additional Context
This issue is particularly impactful for applications where GraphQL is the primary API layer, as it prevents effective monitoring of API performance without falling back to the less feature-rich legacy tracer.
Contribution
I'm happy to submit a PR implementing the suggested fix if the proposed approach is confirmed to be correct.
Summary
The
UnifiedTracemodule for GraphQL does not callContrib::Analytics.set_measured(span)on thegraphql.executespan, which prevents RED (Rate, Errors, Duration) metrics from being generated. This makes it impossible to use standard Datadog monitoring features like the Service Page operations list andtrace.graphql.*metrics.Expected Behavior
When using
with_unified_tracer: true, thegraphql.executespan should:trace.graphql.execute.*metrics (hits, errors, duration)Actual Behavior
graphql.executespan appears correctly in traces with proper resource namestrace.graphql.*metrics are generatedRoot Cause Analysis
Comparing
UnifiedTracewith other integrations that correctly appear as top-level operations:Sidekiq ServerTracer (source):
Rack Middleware (source):
GraphQL UnifiedTrace (source):
The comment on line 86-87 states:
However, setting
TAG_KIND = TAG_SERVERalone is not sufficient to generate RED metrics. The_dd.measured = 1tag (set byset_measured()) is required.Suggested Fix
In
unified_trace.rb, add theset_measured()call in theexecute_querymethod's before lambda:Environment
Additional Context
This issue is particularly impactful for applications where GraphQL is the primary API layer, as it prevents effective monitoring of API performance without falling back to the less feature-rich legacy tracer.
Contribution
I'm happy to submit a PR implementing the suggested fix if the proposed approach is confirmed to be correct.