Skip to content

Commit

Permalink
Fix skip_tracing compatibility
Browse files Browse the repository at this point in the history
`Trace#initialize` was incorrectly assuming that a `@Query` or
`@multiplex` was always defined. However, tracers can be instantiated
manually outside of a Query context (at least to start with).
  • Loading branch information
swalkinshaw committed Apr 11, 2023
1 parent c8cd913 commit a5909d8
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 11 deletions.
31 changes: 20 additions & 11 deletions lib/graphql/metrics/trace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ module Metrics
module Trace
def initialize(**_rest)
super
context = (@multiplex || @query).context
@skip_tracing = context&.fetch(GraphQL::Metrics::SKIP_GRAPHQL_METRICS_ANALYSIS, false)

query_or_multiplex = @query || @multiplex
@skip_tracing = query_or_multiplex.context&.fetch(SKIP_GRAPHQL_METRICS_ANALYSIS, false) if query_or_multiplex
end

# NOTE: These methods come from the graphql ruby gem and are in "chronological" order based on the phases
Expand All @@ -16,60 +17,68 @@ def initialize(**_rest)

# wraps everything below this line; only run once
def execute_multiplex(multiplex:)
return super if @skip_tracing
return super if skip_tracing?(multiplex)
capture_multiplex_start_time { super }
end

# may not trigger if the query is passed in pre-parsed
def lex(query_string:)
return super if @skip_tracing
return super if skip_tracing?
capture_lexing_time { super }
end

# may not trigger if the query is passed in pre-parsed
def parse(query_string:)
return super if @skip_tracing
return super if skip_tracing?
capture_parsing_time { super }
end

def validate(query:, validate:)
return super if @skip_tracing
return super if skip_tracing?(query)
capture_validation_time(query.context) { super }
end

# wraps all `analyze_query`s; only run once
def analyze_multiplex(multiplex:)
return super if @skip_tracing
return super if skip_tracing?(multiplex)
# Ensures that we reset potentially long-lived PreContext objects between multiplexs. We reset at this point
# since all parsing and validation will be done by this point, and a GraphQL::Query::Context will exist.
pre_context.reset
super
end

def analyze_query(query:)
return super if @skip_tracing
return super if skip_tracing?(query)
capture_analysis_time(query.context) { super }
end

def execute_query(query:)
return super if @skip_tracing
return super if skip_tracing?(query)
capture_query_start_time(query.context) { super }
end

def execute_field(field:, query:, ast_node:, arguments:, object:)
return super if @skip_tracing || query.context[SKIP_FIELD_AND_ARGUMENT_METRICS]
return super if skip_tracing?(query) || query.context[SKIP_FIELD_AND_ARGUMENT_METRICS]
return super unless GraphQL::Metrics.timings_capture_enabled?(query.context)
trace_field(GraphQL::Metrics::INLINE_FIELD_TIMINGS, query) { super }
end

def execute_field_lazy(field:, query:, ast_node:, arguments:, object:)
return super if @skip_tracing || query.context[SKIP_FIELD_AND_ARGUMENT_METRICS]
return super if skip_tracing?(query) || query.context[SKIP_FIELD_AND_ARGUMENT_METRICS]
return super unless GraphQL::Metrics.timings_capture_enabled?(query.context)
trace_field(GraphQL::Metrics::LAZY_FIELD_TIMINGS, query) { super }
end

private

def skip_tracing?(query_or_multiplex = nil)
if !defined?(@skip_tracing) && query_or_multiplex
@skip_tracing = query_or_multiplex.context&.fetch(SKIP_GRAPHQL_METRICS_ANALYSIS, false)
end

@skip_tracing
end

PreContext = Struct.new(
:multiplex_start_time,
:multiplex_start_time_monotonic,
Expand Down
14 changes: 14 additions & 0 deletions test/unit/graphql/metrics/trace_integration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,20 @@ def self.parse_error(err, _context)
assert query.multiplex.context[:test_trace_was_executed]
end

test "tracing is skipped when the skip context key is set" do
query = GraphQL::Query.new(
SchemaWithFullMetrics,
kitchen_sink_query_document,
variables: { 'postId': '1', 'titleUpcase': true },
operation_name: 'PostDetails',
context: { SKIP_GRAPHQL_METRICS_ANALYSIS => true }
)
result = query.result.to_h

assert_nil query.multiplex.context.namespace(CONTEXT_NAMESPACE)[QUERY_START_TIME]
assert_nil query.multiplex.context.namespace(CONTEXT_NAMESPACE)[LEXING_DURATION]
end

test 'extracts metrics from queries, as well as their fields and arguments (when using Query#result)' do
context = {}
query = GraphQL::Query.new(
Expand Down

0 comments on commit a5909d8

Please sign in to comment.