Module: GraphQL::Backtrace::Tracer

Defined in:
lib/graphql/backtrace/tracer.rb

Overview

TODO this is not fiber-friendly

Class Method Summary collapse

Class Method Details

.trace(key, metadata) ⇒ Object

Implement the Tracing API.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/graphql/backtrace/tracer.rb', line 9

def trace(key, )
  case key
  when "lex", "parse"
    # No context here, don't have a query yet
    nil
  when "execute_multiplex", "analyze_multiplex"
    # No query context yet
    nil
  when "validate", "analyze_query", "execute_query", "execute_query_lazy"
    push_key = []
    if (query = [:query]) || ((queries = [:queries]) && (query = queries.first))
      push_data = query
      multiplex = query.multiplex
    elsif (multiplex = [:multiplex])
      push_data = multiplex.queries.first
    end
  when "execute_field", "execute_field_lazy"
    query = [:query] || raise(ArgumentError, "Add `legacy: true` to use GraphQL::Backtrace without the interpreter runtime.")
    multiplex = query.multiplex
    push_key = [:path]
    parent_frame = multiplex.context[:graphql_backtrace_contexts][push_key[0..-2]]

    if parent_frame.is_a?(GraphQL::Query)
      parent_frame = parent_frame.context
    end

    push_data = Frame.new(
      query: query,
      path: push_key,
      ast_node: [:ast_node],
      field: [:field],
      object: [:object],
      arguments: [:arguments],
      parent_frame: parent_frame,
    )
  else
    # Custom key, no backtrace data for this
    nil
  end

  if push_data && multiplex
    push_storage = multiplex.context[:graphql_backtrace_contexts] ||= {}
    push_storage[push_key] = push_data
    multiplex.context[:last_graphql_backtrace_context] = push_data
  end

  if key == "execute_multiplex"
    multiplex_context = [:multiplex].context
    begin
      yield
    rescue StandardError => err
      # This is an unhandled error from execution,
      # Re-raise it with a GraphQL trace.
      potential_context = multiplex_context[:last_graphql_backtrace_context]

      if potential_context.is_a?(GraphQL::Query::Context) ||
          potential_context.is_a?(GraphQL::Query::Context::FieldResolutionContext) ||
          potential_context.is_a?(Backtrace::Frame)
        raise TracedError.new(err, potential_context)
      else
        raise
      end
    ensure
      multiplex_context.delete(:graphql_backtrace_contexts)
      multiplex_context.delete(:last_graphql_backtrace_context)
    end
  else
    yield
  end
end