Skip to content

Commit

Permalink
feat!: Cache GraphQL attributes (#867)
Browse files Browse the repository at this point in the history
  • Loading branch information
elenatanasoiu authored Feb 16, 2024
1 parent 4006903 commit c497728
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ module Tracers
# GraphQLTracer contains the OpenTelemetry tracer implementation compatible with
# the GraphQL tracer API
class GraphQLTracer < ::GraphQL::Tracing::PlatformTracing
DEFAULT_HASH = {}.freeze

self.platform_keys = {
'lex' => 'graphql.lex',
'parse' => 'graphql.parse',
Expand Down Expand Up @@ -86,24 +88,60 @@ def config
end

def attributes_for(key, data)
attributes = {}
case key
when 'execute_field', 'execute_field_lazy'
attributes['graphql.field.parent'] = data[:owner]&.graphql_name # owner is the concrete type, not interface
attributes['graphql.field.name'] = data[:field]&.graphql_name
attributes['graphql.lazy'] = key == 'execute_field_lazy'
when 'authorized', 'authorized_lazy'
attributes['graphql.type.name'] = data[:type]&.graphql_name
attributes['graphql.lazy'] = key == 'authorized_lazy'
when 'resolve_type', 'resolve_type_lazy'
attributes['graphql.type.name'] = data[:type]&.graphql_name
attributes['graphql.lazy'] = key == 'resolve_type_lazy'
when 'execute_field'
field_attr_cache = data[:query].context.namespace(:otel_attrs)[:execute_field_attrs] ||= attr_cache do |field|
attrs = {}
attrs['graphql.field.parent'] = field.owner.graphql_name if field.owner.graphql_name
attrs['graphql.field.name'] = field.graphql_name if field.graphql_name
attrs['graphql.lazy'] = false
attrs.freeze
end
field_attr_cache[data[:field]]
when 'execute_field_lazy'
lazy_field_attr_cache = data[:query].context.namespace(:otel_attrs)[:execute_field_lazy_attrs] ||= attr_cache do |field|
attrs = {}
attrs['graphql.field.parent'] = field.owner.graphql_name if field.owner.graphql_name
attrs['graphql.field.name'] = field.graphql_name if field.graphql_name
attrs['graphql.lazy'] = true
attrs.freeze
end
lazy_field_attr_cache[data[:field]]
when 'authorized', 'resolve_type'
type_attrs_cache = data[:context].namespace(:otel_attrs)[:type_attrs] ||= attr_cache do |type|
attrs = {}
attrs['graphql.type.name'] = type.graphql_name if type.graphql_name
attrs['graphql.lazy'] = false
attrs.freeze
end
type_attrs_cache[data[:type]]
when 'authorized_lazy', 'resolve_type_lazy'
type_lazy_attrs_cache = data[:context].namespace(:otel_attrs)[:type_lazy_attrs] ||= attr_cache do |type|
attrs = {}
attrs['graphql.type.name'] = type.graphql_name if type.graphql_name
attrs['graphql.lazy'] = true
attrs.freeze
end
type_lazy_attrs_cache[data[:type]]
when 'execute_query'
attributes['graphql.operation.name'] = data[:query].selected_operation_name if data[:query].selected_operation_name
attributes['graphql.operation.type'] = data[:query].selected_operation.operation_type
attributes['graphql.document'] = data[:query].query_string
attrs = {}
attrs['graphql.document'] = data[:query].query_string if data[:query].query_string
# rubocop:disable Style/SafeNavigation - using safe navigation creates more objects, we want to avoid this
attrs['graphql.operation.type'] = data[:query].selected_operation.operation_type if data[:query].selected_operation && data[:query].selected_operation.operation_type
# rubocop:enable Style/SafeNavigation
attrs['graphql.operation.name'] = data[:query].selected_operation_name || 'anonymous'
attrs.freeze
else
DEFAULT_HASH
end
end

def attr_cache
cache_h = Hash.new do |h, k|
h[k] = yield(k)
end
attributes
cache_h.compare_by_identity
cache_h
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@
it 'omits nil attributes for execute_query' do
expected_attributes = {
'graphql.operation.type' => 'query',
'graphql.document' => '{ simpleField }'
'graphql.document' => '{ simpleField }',
'graphql.operation.name' => 'anonymous'
}

SomeGraphQLAppSchema.execute('{ simpleField }')
Expand Down Expand Up @@ -141,7 +142,7 @@
it 'includes attributes using platform types' do
skip if uses_platform_interfaces?
expected_attributes = {
'graphql.field.parent' => 'Car', # type name, not interface
'graphql.field.parent' => 'Vehicle', # interface name, not type
'graphql.field.name' => 'model',
'graphql.lazy' => false
}
Expand Down

0 comments on commit c497728

Please sign in to comment.