diff --git a/instrumentation/action_view/lib/opentelemetry/instrumentation/action_view.rb b/instrumentation/action_view/lib/opentelemetry/instrumentation/action_view.rb index ef341c0cd..ad42d0dec 100644 --- a/instrumentation/action_view/lib/opentelemetry/instrumentation/action_view.rb +++ b/instrumentation/action_view/lib/opentelemetry/instrumentation/action_view.rb @@ -9,7 +9,7 @@ module OpenTelemetry module Instrumentation - # Contains the OpenTelemetry instrumentation for the ActionView gem + # (see OpenTelemetry::Instrumentation::ActionView::Instrumentation) module ActionView end end diff --git a/instrumentation/action_view/lib/opentelemetry/instrumentation/action_view/instrumentation.rb b/instrumentation/action_view/lib/opentelemetry/instrumentation/action_view/instrumentation.rb index 9087d4475..bb9b60056 100644 --- a/instrumentation/action_view/lib/opentelemetry/instrumentation/action_view/instrumentation.rb +++ b/instrumentation/action_view/lib/opentelemetry/instrumentation/action_view/instrumentation.rb @@ -7,7 +7,42 @@ module OpenTelemetry module Instrumentation module ActionView - # The Instrumentation class contains logic to detect and install the ActionView instrumentation + # The {OpenTelemetry::Instrumentation::ActionView::Instrumentation} class contains logic to detect and install the ActionView instrumentation + # + # Installation and configuration of this instrumentation is done within the + # {https://www.rubydoc.info/gems/opentelemetry-sdk/OpenTelemetry/SDK#configure-instance_method OpenTelemetry::SDK#configure} + # block, calling {https://www.rubydoc.info/gems/opentelemetry-sdk/OpenTelemetry%2FSDK%2FConfigurator:use use()} + # or {https://www.rubydoc.info/gems/opentelemetry-sdk/OpenTelemetry%2FSDK%2FConfigurator:use_all use_all()}. + # + # ## Configuration keys and options + # + # ### `:disallowed_notification_payload_keys` + # + # Specifies an array of keys that should be excluded from the notification payload as span attributes. + # + # ### `:notification_payload_transform` + # + # - `proc` **default** `nil` + # + # Specifies custom proc used to extract span attributes form the notification payload. + # Use this to rename keys, extract nested values, or perform any other custom logic. + # + # ### `:legacy_span_names` + # + # - `boolean` **default** `false` + # + # Specifies whether spans names should use the legacy format where the subscription was reverse ordered and white space separated. (Ex. `action_view render_template`) + # If set to `true`, the span name will match the name of the notification itself. (Ex. `render_template.action_view`) + # + # @example An explicit default configuration + # OpenTelemetry::SDK.configure do |c| + # c.use_all({ + # 'OpenTelemetry::Instrumentation::ActionView' => { + # disallowed_notification_payload_keys: [], + # legacy_span_names: true, + # }, + # }) + # end class Instrumentation < OpenTelemetry::Instrumentation::Base MINIMUM_VERSION = Gem::Version.new('6.1.0') install do |_config| @@ -24,6 +59,7 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base option :disallowed_notification_payload_keys, default: [], validate: :array option :notification_payload_transform, default: nil, validate: :callable + option :legacy_span_names, default: false, validate: :boolean private diff --git a/instrumentation/action_view/lib/opentelemetry/instrumentation/action_view/railtie.rb b/instrumentation/action_view/lib/opentelemetry/instrumentation/action_view/railtie.rb index 276af1106..2c2bf381a 100644 --- a/instrumentation/action_view/lib/opentelemetry/instrumentation/action_view/railtie.rb +++ b/instrumentation/action_view/lib/opentelemetry/instrumentation/action_view/railtie.rb @@ -19,13 +19,16 @@ class Railtie < ::Rails::Railtie config.after_initialize do ::OpenTelemetry::Instrumentation::ActiveSupport::Instrumentation.instance.install({}) + instance = ::OpenTelemetry::Instrumentation::ActionView::Instrumentation.instance + span_name_formatter = instance.config[:legacy_span_names] ? ::OpenTelemetry::Instrumentation::ActiveSupport::LEGACY_NAME_FORMATTER : nil + SUBSCRIPTIONS.each do |subscription_name| - config = ActionView::Instrumentation.instance.config ::OpenTelemetry::Instrumentation::ActiveSupport.subscribe( - ActionView::Instrumentation.instance.tracer, + instance.tracer, subscription_name, - config[:notification_payload_transform], - config[:disallowed_notification_payload_keys] + instance.config[:notification_payload_transform], + instance.config[:disallowed_notification_payload_keys], + span_name_formatter: span_name_formatter ) end end diff --git a/instrumentation/action_view/opentelemetry-instrumentation-action_view.gemspec b/instrumentation/action_view/opentelemetry-instrumentation-action_view.gemspec index 27bd8239f..825106243 100644 --- a/instrumentation/action_view/opentelemetry-instrumentation-action_view.gemspec +++ b/instrumentation/action_view/opentelemetry-instrumentation-action_view.gemspec @@ -26,7 +26,7 @@ Gem::Specification.new do |spec| spec.required_ruby_version = '>= 3.0' spec.add_dependency 'opentelemetry-api', '~> 1.0' - spec.add_dependency 'opentelemetry-instrumentation-active_support', '~> 0.1' + spec.add_dependency 'opentelemetry-instrumentation-active_support', '~> 0.6' spec.add_dependency 'opentelemetry-instrumentation-base', '~> 0.22.1' spec.add_development_dependency 'appraisal', '~> 2.5' diff --git a/instrumentation/active_job/CHANGELOG.md b/instrumentation/active_job/CHANGELOG.md index 4bdc9a478..24527ef69 100644 --- a/instrumentation/active_job/CHANGELOG.md +++ b/instrumentation/active_job/CHANGELOG.md @@ -1,5 +1,9 @@ # Release History: opentelemetry-instrumentation-active_job +### v0.7.4 / 2024-07-30 + +* FIXED: Honour dynamic changes in configuration + ### v0.7.3 / 2024-07-22 * FIXED: ActiveJob::Handlers.unsubscribe diff --git a/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers.rb b/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers.rb index 8b235f1da..70bebf061 100644 --- a/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers.rb +++ b/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers.rb @@ -14,6 +14,8 @@ module Instrumentation module ActiveJob # Module that contains custom event handlers, which are used to generate spans per event module Handlers + EVENT_NAMESPACE = 'active_job' + module_function # Subscribes Event Handlers to relevant ActiveJob notifications @@ -57,7 +59,7 @@ def subscribe } @subscriptions = handlers_by_pattern.map do |key, handler| - ::ActiveSupport::Notifications.subscribe("#{key}.active_job", handler) + ::ActiveSupport::Notifications.subscribe("#{key}.#{EVENT_NAMESPACE}", handler) end end diff --git a/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers/default.rb b/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers/default.rb index 692346aeb..bd05a81ba 100644 --- a/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers/default.rb +++ b/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers/default.rb @@ -40,7 +40,10 @@ def start(name, id, payload) # @param payload [Hash] containing job run information # @return [Hash] with the span and generated context tokens def start_span(name, _id, payload) - span = tracer.start_span(name, attributes: @mapper.call(payload)) + job = payload.fetch(:job) + event_name = name.delete_suffix(".#{EVENT_NAMESPACE}") + span_name = span_name(job, event_name) + span = tracer.start_span(span_name, attributes: @mapper.call(payload)) token = OpenTelemetry::Context.attach(OpenTelemetry::Trace.context_with_span(span)) { span: span, ctx_token: token } @@ -106,6 +109,18 @@ def on_exception(exception, span) def tracer OpenTelemetry::Instrumentation::ActiveJob::Instrumentation.instance.tracer end + + private + + def span_name(job, event_name) + prefix = if @config[:span_naming] == :job_class + job.class.name + else + job.queue_name + end + + "#{prefix} #{event_name}" + end end end end diff --git a/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers/enqueue.rb b/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers/enqueue.rb index 4b1291747..23dab795e 100644 --- a/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers/enqueue.rb +++ b/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers/enqueue.rb @@ -10,6 +10,8 @@ module ActiveJob module Handlers # Handles `enqueue.active_job` and `enqueue_at.active_job` to generate egress spans class Enqueue < Default + EVENT_NAME = 'publish' + # Overrides the `Default#start_span` method to create an egress span # and registers it with the current context # @@ -19,22 +21,11 @@ class Enqueue < Default # @return [Hash] with the span and generated context tokens def start_span(name, _id, payload) job = payload.fetch(:job) - span = tracer.start_span(span_name(job), kind: :producer, attributes: @mapper.call(payload)) + span_name = span_name(job, EVENT_NAME) + span = tracer.start_span(span_name, kind: :producer, attributes: @mapper.call(payload)) OpenTelemetry.propagation.inject(job.__otel_headers) # This must be transmitted over the wire { span: span, ctx_token: OpenTelemetry::Context.attach(OpenTelemetry::Trace.context_with_span(span)) } end - - private - - def span_name(job) - prefix = if @config[:span_naming] == :job_class - job.class.name - else - job.queue_name - end - - "#{prefix} publish" - end end end end diff --git a/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers/perform.rb b/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers/perform.rb index 853281a5e..b617b8ee2 100644 --- a/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers/perform.rb +++ b/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/handlers/perform.rb @@ -10,6 +10,8 @@ module ActiveJob module Handlers # Handles perform.active_job to generate ingress spans class Perform < Default + EVENT_NAME = 'process' + # Overrides the `Default#start_span` method to create an ingress span # and registers it with the current context # @@ -19,10 +21,9 @@ class Perform < Default # @return [Hash] with the span and generated context tokens def start_span(name, _id, payload) job = payload.fetch(:job) + span_name = span_name(job, EVENT_NAME) parent_context = OpenTelemetry.propagation.extract(job.__otel_headers) - span_name = span_name(job) - # TODO: Refactor into a propagation strategy propagation_style = @config[:propagation_style] if propagation_style == :child @@ -48,18 +49,6 @@ def attach_consumer_context(span) OpenTelemetry::Context.attach(internal_context) end - - private - - def span_name(job) - prefix = if @config[:span_naming] == :job_class - job.class.name - else - job.queue_name - end - - "#{prefix} process" - end end end end diff --git a/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/version.rb b/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/version.rb index 4dfdeb2d6..6e4bf337f 100644 --- a/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/version.rb +++ b/instrumentation/active_job/lib/opentelemetry/instrumentation/active_job/version.rb @@ -7,7 +7,7 @@ module OpenTelemetry module Instrumentation module ActiveJob - VERSION = '0.7.3' + VERSION = '0.7.4' end end end diff --git a/instrumentation/active_job/test/opentelemetry/instrumentation/active_job/handlers/discard_test.rb b/instrumentation/active_job/test/opentelemetry/instrumentation/active_job/handlers/discard_test.rb index 89a32b6c6..76c0c82c5 100644 --- a/instrumentation/active_job/test/opentelemetry/instrumentation/active_job/handlers/discard_test.rb +++ b/instrumentation/active_job/test/opentelemetry/instrumentation/active_job/handlers/discard_test.rb @@ -15,7 +15,7 @@ let(:spans) { exporter.finished_spans } let(:publish_span) { spans.find { |s| s.name == 'default publish' } } let(:process_span) { spans.find { |s| s.name == 'default process' } } - let(:discard_span) { spans.find { |s| s.name == 'discard.active_job' } } + let(:discard_span) { spans.find { |s| s.name == 'default discard' } } before do OpenTelemetry::Instrumentation::ActiveJob::Handlers.unsubscribe diff --git a/instrumentation/active_job/test/opentelemetry/instrumentation/active_job/handlers/retry_stopped_test.rb b/instrumentation/active_job/test/opentelemetry/instrumentation/active_job/handlers/retry_stopped_test.rb index 5b4eb774c..a1d931755 100644 --- a/instrumentation/active_job/test/opentelemetry/instrumentation/active_job/handlers/retry_stopped_test.rb +++ b/instrumentation/active_job/test/opentelemetry/instrumentation/active_job/handlers/retry_stopped_test.rb @@ -15,7 +15,7 @@ let(:spans) { exporter.finished_spans } let(:publish_span) { spans.find { |s| s.name == 'default publish' } } let(:process_span) { spans.find { |s| s.name == 'default process' } } - let(:retry_span) { spans.find { |s| s.name == 'retry_stopped.active_job' } } + let(:retry_span) { spans.find { |s| s.name == 'default retry_stopped' } } before do OpenTelemetry::Instrumentation::ActiveJob::Handlers.unsubscribe diff --git a/instrumentation/aws_lambda/CHANGELOG.md b/instrumentation/aws_lambda/CHANGELOG.md index 9e8d73ce0..3166104d3 100644 --- a/instrumentation/aws_lambda/CHANGELOG.md +++ b/instrumentation/aws_lambda/CHANGELOG.md @@ -1,5 +1,9 @@ # Release History: opentelemetry-instrumentation-aws_lambda +### v0.1.1 / 2024-07-30 + +* FIXED: Register lambda span + ### v0.1.0 / 2024-05-11 Initial release. diff --git a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/version.rb b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/version.rb index 6723022fd..2269f5455 100644 --- a/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/version.rb +++ b/instrumentation/aws_lambda/lib/opentelemetry/instrumentation/aws_lambda/version.rb @@ -7,7 +7,7 @@ module OpenTelemetry module Instrumentation module AwsLambda - VERSION = '0.1.0' + VERSION = '0.1.1' end end end diff --git a/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb b/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb index 855b0bc6e..92ae0fc8a 100644 --- a/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb +++ b/instrumentation/aws_lambda/test/opentelemetry/instrumentation_test.rb @@ -71,7 +71,7 @@ _(last_span.instrumentation_scope).must_be_kind_of OpenTelemetry::SDK::InstrumentationScope _(last_span.instrumentation_scope.name).must_equal 'OpenTelemetry::Instrumentation::AwsLambda' - _(last_span.instrumentation_scope.version).must_equal '0.1.0' + _(last_span.instrumentation_scope.version).must_equal OpenTelemetry::Instrumentation::AwsLambda::VERSION _(last_span.hex_span_id.size).must_equal 16 _(last_span.hex_trace_id.size).must_equal 32 diff --git a/instrumentation/base/lib/opentelemetry/instrumentation/base.rb b/instrumentation/base/lib/opentelemetry/instrumentation/base.rb index 8c9ac0e3f..ddf828955 100644 --- a/instrumentation/base/lib/opentelemetry/instrumentation/base.rb +++ b/instrumentation/base/lib/opentelemetry/instrumentation/base.rb @@ -304,7 +304,7 @@ def config_options(user_config) h[option_name] = option[:default] end - dropped_config_keys = user_config.keys - validated_config.keys + dropped_config_keys = user_config.keys - validated_config.keys - [:enabled] OpenTelemetry.logger.warn("Instrumentation #{name} ignored the following unknown configuration options #{dropped_config_keys}") unless dropped_config_keys.empty? validated_config diff --git a/instrumentation/graphql/CHANGELOG.md b/instrumentation/graphql/CHANGELOG.md index f18b62e02..4aae6d42d 100644 --- a/instrumentation/graphql/CHANGELOG.md +++ b/instrumentation/graphql/CHANGELOG.md @@ -1,5 +1,9 @@ # Release History: opentelemetry-instrumentation-graphql +### v0.28.4 / 2024-07-30 + +* FIXED: Add super calls to GraphqlTrace + ### v0.28.3 / 2024-07-23 * DOCS: Add cspell to CI diff --git a/instrumentation/graphql/lib/opentelemetry/instrumentation/graphql/tracers/graphql_trace.rb b/instrumentation/graphql/lib/opentelemetry/instrumentation/graphql/tracers/graphql_trace.rb index 70c966623..cb82bf2c7 100644 --- a/instrumentation/graphql/lib/opentelemetry/instrumentation/graphql/tracers/graphql_trace.rb +++ b/instrumentation/graphql/lib/opentelemetry/instrumentation/graphql/tracers/graphql_trace.rb @@ -60,15 +60,15 @@ def initialize(trace_scalars: false, **_options) end def execute_multiplex(multiplex:, &block) - tracer.in_span('graphql.execute_multiplex', &block) + tracer.in_span('graphql.execute_multiplex') { super } end def lex(query_string:, &block) - tracer.in_span('graphql.lex', &block) + tracer.in_span('graphql.lex') { super } end def parse(query_string:, &block) - tracer.in_span('graphql.parse', &block) + tracer.in_span('graphql.parse') { super } end def validate(query:, validate:, &block) @@ -89,11 +89,11 @@ def validate(query:, validate:, &block) end def analyze_multiplex(multiplex:, &block) - tracer.in_span('graphql.analyze_multiplex', &block) + tracer.in_span('graphql.analyze_multiplex') { super } end def analyze_query(query:, &block) - tracer.in_span('graphql.analyze_query', &block) + tracer.in_span('graphql.analyze_query') { super } end def execute_query(query:, &block) @@ -102,11 +102,13 @@ def execute_query(query:, &block) attributes['graphql.operation.type'] = query.selected_operation.operation_type attributes['graphql.document'] = query.query_string - tracer.in_span('graphql.execute_query', attributes: attributes, &block) + tracer.in_span('graphql.execute_query', attributes: attributes) do + super + end end def execute_query_lazy(query:, multiplex:, &block) - tracer.in_span('graphql.execute_query_lazy', &block) + tracer.in_span('graphql.execute_query_lazy') { super } end def execute_field(field:, query:, ast_node:, arguments:, object:, &block) @@ -133,7 +135,7 @@ def authorized(query:, type:, object:, &block) attributes = @_otel_type_attrs_cache[type] - tracer.in_span(platform_key, attributes: attributes, &block) + tracer.in_span(platform_key, attributes: attributes) { super } end def authorized_lazy(query:, type:, object:, &block) @@ -141,19 +143,19 @@ def authorized_lazy(query:, type:, object:, &block) return super unless platform_key attributes = @_otel_lazy_type_attrs_cache[type] - tracer.in_span(platform_key, attributes: attributes, &block) + tracer.in_span(platform_key, attributes: attributes) { super } end def resolve_type(query:, type:, object:, &block) platform_key = @_otel_resolve_type_key_cache[type] attributes = @_otel_type_attrs_cache[type] - tracer.in_span(platform_key, attributes: attributes, &block) + tracer.in_span(platform_key, attributes: attributes) { super } end def resolve_type_lazy(query:, type:, object:, &block) platform_key = @_otel_resolve_type_key_cache[type] attributes = @_otel_lazy_type_attrs_cache[type] - tracer.in_span(platform_key, attributes: attributes, &block) + tracer.in_span(platform_key, attributes: attributes) { super } end private diff --git a/instrumentation/graphql/lib/opentelemetry/instrumentation/graphql/version.rb b/instrumentation/graphql/lib/opentelemetry/instrumentation/graphql/version.rb index 3792724a8..da398eb73 100644 --- a/instrumentation/graphql/lib/opentelemetry/instrumentation/graphql/version.rb +++ b/instrumentation/graphql/lib/opentelemetry/instrumentation/graphql/version.rb @@ -7,7 +7,7 @@ module OpenTelemetry module Instrumentation module GraphQL - VERSION = '0.28.3' + VERSION = '0.28.4' end end end diff --git a/instrumentation/graphql/test/instrumentation/graphql/tracers/graphql_trace_test.rb b/instrumentation/graphql/test/instrumentation/graphql/tracers/graphql_trace_test.rb index 22e194036..4fb0e9d85 100644 --- a/instrumentation/graphql/test/instrumentation/graphql/tracers/graphql_trace_test.rb +++ b/instrumentation/graphql/test/instrumentation/graphql/tracers/graphql_trace_test.rb @@ -361,6 +361,41 @@ def platform_field_key(field) _(custom_events).must_equal(true) end end + + module CustomTrace + def execute_multiplex(multiplex:) + multiplex.context[:custom_trace_execute_multiplex_ran] = true + super + end + + def execute_query(query:) + query.context[:custom_trace_execute_query_ran] = true + super + end + end + + it 'works with other trace modules' do + [GraphQL::Schema, SomeOtherGraphQLAppSchema, SomeGraphQLAppSchema].each(&:_reset_tracer_for_testing) + instrumentation.instance_variable_set(:@installed, false) + + custom_trace_schema = Class.new(GraphQL::Schema) do + query(Class.new(GraphQL::Schema::Object) do + graphql_name 'Query' + field :int, Integer, fallback_value: 5 + end) + + trace_with(CustomTrace) + end + + instrumentation.install({ schemas: [custom_trace_schema] }) + res = custom_trace_schema.execute('{ int }') + assert_equal 5, res['data']['int'], 'The query ran successfully' + + assert res.context[:custom_trace_execute_query_ran], 'The custom execute_query hook ran' + assert res.query.multiplex.context[:custom_trace_execute_multiplex_ran], 'The custom execute_multiplex hook ran' + + assert spans.find { |s| s.name == 'graphql.execute_query' }, 'OpenTelementry ran' + end end end end