Skip to content

Commit 9795587

Browse files
authored
Merge pull request #1151 from tildeio/graphql-2.5
fix graphql instrumentation
2 parents 39a51b7 + 9f16c21 commit 9795587

File tree

4 files changed

+118
-49
lines changed

4 files changed

+118
-49
lines changed

gemfiles/Gemfile.additional

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ gem "delayed_job_active_record", require: false
44
gem "excon"
55
gem "faraday"
66
gem "graphiti", git: "https://github.com/graphiti-api/graphiti.git"
7-
gem "graphql", "~> 2.0.18"
7+
gem "graphql", "~> 2.5.0"
88
gem "httpclient"
99
gem "rexml"
1010
gem "sequel", "> 0"

lib/skylight/normalizers/graphql/base.rb

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,40 @@ class Validate < Base
5959
register_graphql
6060
end
6161

62-
class ExecuteMultiplex < Base
62+
class Execute < Base
6363
register_graphql
6464

65-
def normalize_after(trace, _span, _name, payload)
65+
# This is a new, combined normalizer for execute_query and execute_multiplex,
66+
# to be used for graphql >= 2.5
67+
#
68+
def normalize(trace, name, payload)
69+
if payload[:query]
70+
_execute_query_normalize(trace, name, payload)
71+
else
72+
[CAT, "graphql.#{key}", nil]
73+
end
74+
end
75+
76+
def normalize_after(trace, span, name, payload)
77+
if payload[:multiplex]
78+
_execute_multiplex_normalize_after(trace, span, name, payload)
79+
end
80+
end
81+
82+
private
83+
84+
def _execute_query_normalize(trace, _name, payload)
85+
query_name = extract_query_name(payload[:query])
86+
87+
meta = { mute_children: true } if query_name == ANONYMOUS
88+
# This is probably always overriden by execute_multiplex#normalize_after,
89+
# but in the case of a single query, it will be the same value anyway.
90+
trace.endpoint = "graphql:#{query_name}"
91+
92+
[CAT, "graphql.#{key}: #{query_name}", nil, meta]
93+
end
94+
95+
def _execute_multiplex_normalize_after(trace, _span, _name, payload)
6696
# This is in normalize_after because the queries may not have
6797
# an assigned operation name before they are executed.
6898
# For example, if you send a single query with a defined operation name, e.g.:
@@ -93,24 +123,18 @@ def normalize_after(trace, _span, _name, payload)
93123
end
94124
end
95125

96-
class AnalyzeQuery < Base
126+
class ExecuteQuery < Execute
97127
register_graphql
98128
end
99129

100-
class ExecuteQuery < Base
130+
class ExecuteMultiplex < Execute
101131
register_graphql
102132

103-
def normalize(trace, _name, payload)
104-
query_name = extract_query_name(payload[:query])
105-
106-
meta = { mute_children: true } if query_name == ANONYMOUS
107-
108-
# This is probably always overriden by execute_multiplex#normalize_after,
109-
# but in the case of a single query, it will be the same value anyway.
110-
trace.endpoint = "graphql:#{query_name}"
133+
# see behavior in Execute#_multiplex_normalize_after
134+
end
111135

112-
[CAT, "graphql.#{key}: #{query_name}", nil, meta]
113-
end
136+
class AnalyzeQuery < Base
137+
register_graphql
114138
end
115139

116140
class ExecuteQueryLazy < ExecuteQuery

lib/skylight/probes/graphql.rb

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,48 @@ def execute_multiplex(**metadata, &blk)
3535
end
3636
end
3737

38+
# GraphQL versions >= 2.5 are missing this notification
39+
module ExecuteQueryNotification
40+
def execute_query(**metadata, &blk)
41+
if @notifications_engine
42+
@notifications_engine.instrument("execute_query.graphql", metadata, &blk)
43+
elsif @notifications
44+
@notifications.instrument("execute_query.graphql", metadata, &blk)
45+
else
46+
# safety fallback in case graphql's authors unexpectedly rename @notifications_engine or @notifications
47+
super
48+
end
49+
end
50+
end
51+
52+
# GraphQL versions >= 2.5 are missing this notification
53+
module ExecuteQueryLazyNotification
54+
def execute_query_lazy(**metadata, &blk)
55+
if @notifications_engine
56+
@notifications_engine.instrument("execute_query_lazy.graphql", metadata, &blk)
57+
elsif @notifications
58+
@notifications.instrument("execute_query_lazy.graphql", metadata, &blk)
59+
else
60+
# safety fallback in case graphql's authors unexpectedly rename @notifications_engine or @notifications
61+
super
62+
end
63+
end
64+
end
65+
66+
# GraphQL versions >= 2.5 are missing this notification
67+
module AnalyzeQueryNotification
68+
def analyze_query(**metadata, &blk)
69+
if @notifications_engine
70+
@notifications_engine.instrument("analyze_query.graphql", metadata, &blk)
71+
elsif @notifications
72+
@notifications.instrument("analyze_query.graphql", metadata, &blk)
73+
else
74+
# safety fallback in case graphql's authors unexpectedly rename @notifications_engine or @notifications
75+
super
76+
end
77+
end
78+
end
79+
3880
module ClassMethods
3981
def new_trace(*, **)
4082
unless @__sk_instrumentation_installed
@@ -44,6 +86,18 @@ def new_trace(*, **)
4486
trace_with(ExecuteMultiplexNotification)
4587
end
4688

89+
unless ::GraphQL::Tracing::ActiveSupportNotificationsTrace.instance_methods.include?(:execute_query)
90+
trace_with(ExecuteQueryNotification)
91+
end
92+
93+
unless ::GraphQL::Tracing::ActiveSupportNotificationsTrace.instance_methods.include?(:execute_query_lazy)
94+
trace_with(ExecuteQueryLazyNotification)
95+
end
96+
97+
unless ::GraphQL::Tracing::ActiveSupportNotificationsTrace.instance_methods.include?(:analyze_query)
98+
trace_with(AnalyzeQueryNotification)
99+
end
100+
47101
@__sk_instrumentation_installed = true
48102
end
49103

spec/integration/graphql_spec.rb

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@
1111
end
1212

1313
if enable
14-
def test_interpreter_schema?
15-
defined?(GraphQL::Execution::Interpreter)
14+
def graphql_2_5?
15+
GraphQL::VERSION >= Gem::Version.new("2.5.0")
16+
end
17+
18+
def multiplex_event
19+
graphql_2_5? ? "graphql.execute" : "graphql.execute_multiplex"
1620
end
1721

1822
describe "graphql integration" do
@@ -309,21 +313,15 @@ def make_graphql_request(query:, variables: {}, **params)
309313
call env("/", method: :POST, params: { query: query, variables: variables, **params })
310314
end
311315

312-
# Handles expected analysis events for legacy style (GraphQL 1.9.x)
313-
# and new interpreter style (GraphQL >= 1.9.x when using GraphQL::Execution::Interpreter).
314316
def expected_analysis_events(query_count = 1)
315-
events = [%w[app.graphql graphql.lex], %w[app.graphql graphql.parse], %w[app.graphql graphql.validate]].freeze
316-
317-
analyze_event = %w[app.graphql graphql.analyze_query]
318-
event_style = expectation_event_style
319-
case event_style
320-
when :grouped
321-
events.cycle(query_count).to_a.tap { |a| a.concat([analyze_event].cycle(query_count).to_a) }
322-
when :inline
323-
[*events, analyze_event].cycle(query_count)
324-
else
325-
raise "Unexpected expectation_event_style: #{event_style}"
326-
end.to_a
317+
events = graphql_2_5? ? [] : [%w[app.graphql graphql.lex]]
318+
events |= [
319+
%w[app.graphql graphql.parse],
320+
%w[app.graphql graphql.validate],
321+
%w[app.graphql graphql.analyze_query]
322+
]
323+
324+
events.cycle(query_count).to_a
327325
end
328326

329327
let(:query_inner) { "#{TestApp.format_field_name("someDragonflies")} { name }" }
@@ -349,7 +347,7 @@ def expected_analysis_events(query_count = 1)
349347
expect(data).to eq(
350348
[
351349
["app.rack.request", nil],
352-
%w[app.graphql graphql.execute_multiplex],
350+
["app.graphql", multiplex_event],
353351
*expected_analysis_events,
354352
["app.graphql", "graphql.execute_query: #{query_name}"],
355353
["app.graphql", "graphql.execute_query_lazy: #{query_name}"]
@@ -377,7 +375,7 @@ def expected_analysis_events(query_count = 1)
377375
expect(data).to eq(
378376
[
379377
["app.rack.request", nil],
380-
%w[app.graphql graphql.execute_multiplex],
378+
["app.graphql", multiplex_event],
381379
*expected_analysis_events,
382380
["app.graphql", "graphql.execute_query: #{query_name}"],
383381
["db.sql.query", "SELECT FROM species"],
@@ -414,7 +412,7 @@ def expected_analysis_events(query_count = 1)
414412
expect(data).to eq(
415413
[
416414
["app.rack.request", nil],
417-
%w[app.graphql graphql.execute_multiplex],
415+
["app.graphql", multiplex_event],
418416
*expected_analysis_events,
419417
["app.graphql", "graphql.execute_query: #{query_name}"],
420418
["db.sql.query", "SELECT FROM species"],
@@ -448,7 +446,7 @@ def expected_analysis_events(query_count = 1)
448446
expect(data).to eq(
449447
[
450448
["app.rack.request", nil],
451-
%w[app.graphql graphql.execute_multiplex],
449+
["app.graphql", multiplex_event],
452450
*expected_analysis_events(3),
453451
["app.graphql", "graphql.execute_query: #{query_name}"],
454452
["app.graphql", "graphql.execute_query: #{query_name}"],
@@ -479,7 +477,7 @@ def expected_analysis_events(query_count = 1)
479477
expect(data).to eq(
480478
[
481479
["app.rack.request", nil],
482-
%w[app.graphql graphql.execute_multiplex],
480+
["app.graphql", multiplex_event],
483481
*expected_analysis_events(3),
484482
*%w[query-0 query-1 query-2]
485483
.map do |qn|
@@ -518,7 +516,7 @@ def expected_analysis_events(query_count = 1)
518516
expect(data).to eq(
519517
[
520518
["app.rack.request", nil],
521-
%w[app.graphql graphql.execute_multiplex],
519+
["app.graphql", multiplex_event],
522520
*expected_analysis_events(4),
523521
["app.graphql", "graphql.execute_query: #{query_name}"],
524522
["app.graphql", "graphql.execute_query: #{query_name}"],
@@ -557,7 +555,7 @@ def expected_analysis_events(query_count = 1)
557555
expect(data).to eq(
558556
[
559557
["app.rack.request", nil],
560-
%w[app.graphql graphql.execute_multiplex],
558+
["app.graphql", multiplex_event],
561559
*expected_analysis_events(2),
562560
["app.graphql", "graphql.execute_query: myFavoriteDragonflies"],
563561
["db.sql.query", "SELECT FROM species"],
@@ -595,7 +593,7 @@ def expected_analysis_events(query_count = 1)
595593
expect(data).to eq(
596594
[
597595
["app.rack.request", nil],
598-
%w[app.graphql graphql.execute_multiplex],
596+
["app.graphql", multiplex_event],
599597
*expected_analysis_events(2)[0..-2],
600598
["app.graphql", "graphql.execute_query: myFavoriteDragonflies"],
601599
["db.sql.query", "SELECT FROM species"],
@@ -630,7 +628,7 @@ def expected_analysis_events(query_count = 1)
630628
expect(data).to eq(
631629
[
632630
["app.rack.request", nil],
633-
%w[app.graphql graphql.execute_multiplex],
631+
["app.graphql", multiplex_event],
634632
*expected_analysis_events(2).reject { |_, e| e["graphql.analyze"] },
635633
%w[app.graphql graphql.execute_query_lazy.multiplex]
636634
]
@@ -672,7 +670,7 @@ def expected_analysis_events(query_count = 1)
672670
expect(data).to eq(
673671
[
674672
["app.rack.request", nil],
675-
%w[app.graphql graphql.execute_multiplex],
673+
["app.graphql", multiplex_event],
676674
*expected_analysis_events,
677675
["app.graphql", "graphql.execute_query: #{mutation_name}"],
678676
["db.sql.query", "SELECT FROM genera"],
@@ -688,14 +686,7 @@ def expected_analysis_events(query_count = 1)
688686
end
689687

690688
configs = []
691-
692-
configs << { schema: :InterpreterSchema, expectation_event_style: :inline } if test_interpreter_schema?
693-
694-
# GraphQL::Execution::Interpreter became the default as of 1.12, so we do not need to
695-
# test an additional schema for versions >= 1.12.
696-
if Gem::Version.new(GraphQL::VERSION) < Gem::Version.new("1.12")
697-
configs << { schema: :TestAppSchema, expectation_event_style: :grouped }
698-
end
689+
configs << { schema: :InterpreterSchema, expectation_event_style: :inline }
699690

700691
configs.each do |config|
701692
context config[:schema].to_s do

0 commit comments

Comments
 (0)