Class: GraphQL::Tracing::DetailedTrace

Inherits:
Object
  • Object
show all
Defined in:
lib/graphql/tracing/detailed_trace.rb,
lib/graphql/tracing/detailed_trace/redis_backend.rb,
lib/graphql/tracing/detailed_trace/memory_backend.rb

Overview

DetailedTrace can make detailed profiles for a subset of production traffic.

When MySchema.detailed_trace?(query) returns true, a profiler-specific trace_mode: ... will be used for the query, overriding the one in context[:trace_mode].

By default, the detailed tracer calls .inspect on application objects returned from fields. You can customize this behavior by extending DetailedTrace and overriding #inspect_object. You can opt out of debug annotations entirely with use ..., debug: false or for a single query with context: { detailed_trace_debug: false }.

Redis: The sampler stores its results in a provided Redis database. Depending on your needs, You can configure this database to retain all data (persistent) or to expire data according to your rules. If you need to save traces indefinitely, you can download them from Perfetto after opening them there.

Examples:

Adding the sampler to your schema

class MySchema < GraphQL::Schema
  # Add the sampler:
  use GraphQL::Tracing::DetailedTrace, redis: Redis.new(...), limit: 100

  # And implement this hook to tell it when to take a sample:
  def self.detailed_trace?(query)
    # Could use `query.context`, `query.selected_operation_name`, `query.query_string` here
    # Could call out to Flipper, etc
    rand <= 0.000_1 # one in ten thousand
  end
end

Customizing debug output in traces

class CustomDetailedTrace < GraphQL::Tracing::DetailedTrace
  def inspect_object(object)
    if object.is_a?(SomeThing)
      # handle it specially ...
    else
      super
     end
  end
end

disabling debug annotations completely

use DetailedTrace, debug: false, ...

disabling debug annotations for one query

MySchema.execute(query_str, context: { detailed_trace_debug: false })

See Also:

Defined Under Namespace

Classes: MemoryBackend, RedisBackend, StoredTrace

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(storage:, trace_mode:, debug:) ⇒ DetailedTrace

Returns a new instance of DetailedTrace.



69
70
71
72
73
# File 'lib/graphql/tracing/detailed_trace.rb', line 69

def initialize(storage:, trace_mode:, debug:)
  @storage = storage
  @trace_mode = trace_mode
  @debug = debug
end

Instance Attribute Details

#trace_modeSymbol (readonly)

Returns The trace mode to use when Schema.detailed_trace? returns true.

Returns:



76
77
78
# File 'lib/graphql/tracing/detailed_trace.rb', line 76

def trace_mode
  @trace_mode
end

Class Method Details

.debug?true

Default debug setting

Returns:

  • (true)


124
125
126
# File 'lib/graphql/tracing/detailed_trace.rb', line 124

def self.debug?
  true
end

.inspect_object(object) ⇒ Object



114
115
116
117
118
119
120
# File 'lib/graphql/tracing/detailed_trace.rb', line 114

def self.inspect_object(object)
  if defined?(ActiveRecord::Relation) && object.is_a?(ActiveRecord::Relation)
    "#{object.class}, .to_sql=#{object.to_sql.inspect}"
  else
    object.inspect
  end
end

.use(schema, trace_mode: :profile_sample, memory: false, debug: debug?, , redis: nil, limit: nil) ⇒ Object

Parameters:

  • redis (Redis) (defaults to: nil)

    If provided, profiles will be stored in Redis for later review

  • limit (Integer) (defaults to: nil)

    A maximum number of profiles to store

  • debug (Boolean) (defaults to: debug?, )

    if false, it won’t create debug annotations in Perfetto traces (reduces overhead)



56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/graphql/tracing/detailed_trace.rb', line 56

def self.use(schema, trace_mode: :profile_sample, memory: false, debug: debug?, redis: nil, limit: nil)
  storage = if redis
    RedisBackend.new(redis: redis, limit: limit)
  elsif memory
    MemoryBackend.new(limit: limit)
  else
    raise ArgumentError, "Pass `redis: ...` to store traces in Redis for later review"
  end
  detailed_trace = self.new(storage: storage, trace_mode: trace_mode, debug: debug)
  schema.detailed_trace = detailed_trace
  schema.trace_with(PerfettoTrace, mode: trace_mode, save_profile: true)
end

Instance Method Details

#debug?Boolean

Returns:

  • (Boolean)


84
85
86
# File 'lib/graphql/tracing/detailed_trace.rb', line 84

def debug?
  @debug
end

#delete_all_tracesvoid

This method returns an undefined value.



106
107
108
# File 'lib/graphql/tracing/detailed_trace.rb', line 106

def delete_all_traces
  @storage.delete_all_traces
end

#delete_trace(id) ⇒ void

This method returns an undefined value.



101
102
103
# File 'lib/graphql/tracing/detailed_trace.rb', line 101

def delete_trace(id)
  @storage.delete_trace(id)
end

#find_trace(id) ⇒ StoredTrace?

Returns:



96
97
98
# File 'lib/graphql/tracing/detailed_trace.rb', line 96

def find_trace(id)
  @storage.find_trace(id)
end

#inspect_object(object) ⇒ Object



110
111
112
# File 'lib/graphql/tracing/detailed_trace.rb', line 110

def inspect_object(object)
  self.class.inspect_object(object)
end

#save_trace(operation_name, duration_ms, begin_ms, trace_data) ⇒ String

Returns ID of saved trace.

Returns:

  • (String)

    ID of saved trace



79
80
81
# File 'lib/graphql/tracing/detailed_trace.rb', line 79

def save_trace(operation_name, duration_ms, begin_ms, trace_data)
  @storage.save_trace(operation_name, duration_ms, begin_ms, trace_data)
end

#traces(last: nil, before: nil) ⇒ Enumerable<StoredTrace>

Parameters:

  • last (Integer) (defaults to: nil)
  • before (Integer) (defaults to: nil)

    Timestamp in milliseconds since epoch

Returns:



91
92
93
# File 'lib/graphql/tracing/detailed_trace.rb', line 91

def traces(last: nil, before: nil)
  @storage.traces(last: last, before: before)
end