lib/opentelemetry/instrumentation/graphql/tracers/graphql_tracer.rb in opentelemetry-instrumentation-graphql-0.27.0 vs lib/opentelemetry/instrumentation/graphql/tracers/graphql_tracer.rb in opentelemetry-instrumentation-graphql-0.28.0

- old
+ new

@@ -11,10 +11,12 @@ module GraphQL 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', 'validate' => 'graphql.validate', 'analyze_query' => 'graphql.analyze_query', @@ -84,27 +86,63 @@ def config GraphQL::Instrumentation.instance.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 - attributes + end + + def attr_cache + cache_h = Hash.new do |h, k| + h[k] = yield(k) + end + cache_h.compare_by_identity + cache_h end end end end end