基本运作

主要是patch ::ActiveJob::Base

# opentelemetry-instrumentation-active_job-0.1.5/lib/opentelemetry/instrumentation/active_job/patches/base.rb
module OpenTelemetry
  module Instrumentation
    module ActiveJob
      class Instrumentation < OpenTelemetry::Instrumentation::Base
        install do |_config|
          require_dependencies
          patch_activejob
        end

        def patch_activejob
          ::ActiveJob::Base.prepend(Patches::Base)
          ::ActiveJob::Base.prepend(Patches::ActiveJobCallbacks)
        end
      end
    end
  end
end

Patches::BaseActiveJob增加metadata属性,以便传递trace-id

# opentelemetry-instrumentation-active_job-0.1.5/lib/opentelemetry/instrumentation/active_job/patches/base.rb
module OpenTelemetry
  module Instrumentation
    module ActiveJob
      module Patches
        module Base
          def self.prepended(base)
            base.class_eval do
              attr_accessor :metadata
            end
          end

          def initialize(*args)
            @metadata = {}
            super
          end
        end
      end
    end
  end
end

Patches::ActiveJobCallbacks在入队时写入trace-id到metadata,出队时读取,还原成extracted_context,然后在此extracted_context的基础上in_span,关联上层

# opentelemetry-instrumentation-active_job-0.1.5/lib/opentelemetry/instrumentation/active_job/patches/active_job_callbacks.rb
module OpenTelemetry
  module Instrumentation
    module ActiveJob
      module Patches
        module ActiveJobCallbacks
          def self.prepended(base)
            base.class_eval do
              around_enqueue do |job, block|
                # ...
                otel_tracer.in_span(span_name, attributes: span_attributes, kind: span_kind) do
                  OpenTelemetry.propagation.inject(job.metadata)
                  block.call
                end
              end

              around_perform do |job, block|
                # ...
                extracted_context = OpenTelemetry.propagation.extract(job.metadata)
                OpenTelemetry::Context.with_current(extracted_context) do
                  if otel_config[:propagation_style] == :child
                    # ...
                  else
                    span_links = []
                    if otel_config[:propagation_style] == :link
                      span_context = OpenTelemetry::Trace.current_span(extracted_context).context
                      span_links << OpenTelemetry::Trace::Link.new(span_context) if span_context.valid?
                    end

                    root_span = otel_tracer.start_root_span(span_name, attributes: span_attributes, links: span_links, kind: span_kind)
                    OpenTelemetry::Trace.with_span(root_span) do |span|
                      # ...
                    end
                  end
                end
              end
            end
          end
        end
      end
    end
  end
end

用link或是child

通过{propagation_style: :xxx}配置,可选child\link\none

# opentelemetry-instrumentation-active_job-0.4.0/lib/opentelemetry/instrumentation/active_job/patches/active_job_callbacks.rb
def perform_now
  # ...
  OpenTelemetry::Context.with_current(extracted_context) do
    if otel_config[:propagation_style] == :child
      otel_tracer.in_span(span_name, attributes: span_attributes, kind: span_kind) do |span|
        span.set_attribute('messaging.active_job.executions', executions_count)
        super
      end
    else
      span_links = []
      if otel_config[:propagation_style] == :link
        span_context = OpenTelemetry::Trace.current_span(extracted_context).context
        span_links << OpenTelemetry::Trace::Link.new(span_context) if span_context.valid?
      end

      root_span = otel_tracer.start_root_span(span_name, attributes: span_attributes, links: span_links, kind: span_kind)
      OpenTelemetry::Trace.with_span(root_span) do |span|
        # ...
      end
    end
  end
end

更改span名字

默认情况下span名字是“队列名 send”和“队列名 process”

# opentelemetry-instrumentation-active_job-0.1.5/lib/opentelemetry/instrumentation/active_job/patches/active_job_callbacks.rb
around_enqueue do |job, block|
  # ...
  span_name = "#{otel_config[:span_naming] == :job_class ? job.class : job.queue_name} send"
  otel_tracer.in_span(span_name, attributes: span_attributes, kind: span_kind) do
    # ...
  end
end

可以配置成“类名 send”和“类名 process”

OpenTelemetry::SDK.configure do |c|
  c.use_all({
    'OpenTelemetry::Instrumentation::ActiveJob' => {
      span_naming: :job_class
    }
  })
end