Commit 6daeb286 authored by Bob Van Landuyt's avatar Bob Van Landuyt 💬
Browse files

Merge branch 'qmnguyen0711/unwrap-active-jobs' into 'master'

Unwrap ActiveJob wrapper in Sidekiq tracing spans

See merge request gitlab-org/labkit-ruby!52
parents 6c3df142 b250e258
Loading
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@ module Labkit
          SPAN_KIND = "client"

          def call(_worker_class, job, _queue, _redis_pool)
            Labkit::Tracing::TracingUtils.with_tracing(operation_name: "sidekiq:#{job["class"]}", tags: tags_from_job(job, SPAN_KIND)) do |span|
            Labkit::Tracing::TracingUtils.with_tracing(operation_name: "sidekiq:#{job_class(job)}", tags: tags_from_job(job, SPAN_KIND)) do |span|
              # Inject the details directly into the job
              Labkit::Tracing::TracingUtils.tracer.inject(span.context, OpenTracing::FORMAT_TEXT_MAP, job)

+1 −1
Original line number Diff line number Diff line
@@ -17,7 +17,7 @@ module Labkit
          def call(_worker, job, _queue)
            context = Labkit::Tracing::TracingUtils.tracer.extract(OpenTracing::FORMAT_TEXT_MAP, job)

            Labkit::Tracing::TracingUtils.with_tracing(operation_name: "sidekiq:#{job["class"]}", child_of: context, tags: tags_from_job(job, SPAN_KIND)) { |_span| yield }
            Labkit::Tracing::TracingUtils.with_tracing(operation_name: "sidekiq:#{job_class(job)}", child_of: context, tags: tags_from_job(job, SPAN_KIND)) { |_span| yield }
          end
        end
      end
+14 −1
Original line number Diff line number Diff line
@@ -6,15 +6,28 @@ module Labkit
      module Tracing
        # SidekiqCommon is a mixin for the sidekiq middleware components
        module SidekiqCommon
          def job_class(job)
            # Active Job wrapping can be found at
            # https://github.com/rails/rails/blob/v6.0.3.1/activejob/lib/active_job/queue_adapters/sidekiq_adapter.rb
            job["wrapped"].presence || job["class"].presence || "undefined"
          end

          def wrapped?(job)
            job["wrapped"].present?
          end

          def tags_from_job(job, kind)
            {
            tags = {
              "component" => "sidekiq",
              "span.kind" => kind,
              "sidekiq.wrapped" => wrapped?(job),
              "sidekiq.queue" => job["queue"],
              "sidekiq.jid" => job["jid"],
              "sidekiq.retry" => job["retry"].to_s,
              "sidekiq.args" => job["args"]&.join(", "),
            }
            tags["sidekiq.at"] = job["at"] if job["at"]
            tags
          end
        end
      end
+99 −4
Original line number Diff line number Diff line
@@ -3,14 +3,24 @@
describe Labkit::Middleware::Sidekiq::Tracing::Client do
  describe "#call" do
    let(:worker_class) { "test_worker_class" }
    let(:job) { { "class" => "jobclass", "queue" => "jobqueue", "retry" => 0, "args" => %w[1 2 3] } }
    let(:queue) { "test_queue" }
    let(:redis_pool) { double("redis_pool") }
    let(:custom_error) { Class.new(StandardError) }
    let(:span) { OpenTracing.start_span("test", ignore_active_scope: true) }

    subject { described_class.new }

    it "propagates exceptions" do
      custom_error = Class.new(StandardError)
      expect do
        subject.call(worker_class, { "class" => "jobclass", "queue" => "jobqueue", "retry" => 0, "args" => [] }, queue, redis_pool) do
          raise custom_error
        end
      end.to raise_error(custom_error)
    end

    context "when the job is scheduled directly" do
      let(:job) { { "class" => "jobclass", "queue" => "jobqueue", "retry" => 0, "args" => %w[1 2 3] } }

      it "yields" do
        expect(Labkit::Tracing::TracingUtils).to receive(:with_tracing)
                                                   .with(
@@ -22,14 +32,99 @@ describe Labkit::Middleware::Sidekiq::Tracing::Client do
                                                       "sidekiq.jid" => nil,
                                                       "sidekiq.retry" => "0",
                                                       "sidekiq.args" => "1, 2, 3",
                                                       "sidekiq.wrapped" => false,
                                                     },
                                                   ).and_yield(span)

        expect { |b| subject.call(worker_class, job, queue, redis_pool, &b) }.to yield_control
      end
    end

    it "propagates exceptions" do
      expect { subject.call(worker_class, job, queue, redis_pool) { raise custom_error } }.to raise_error(custom_error)
    context "when the job is scheduled via ActiveJob" do
      let(:job) do
        {
          "class" => "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper",
          "queue" => "jobqueue",
          "retry" => 0,
          "args" => %w[1 2 3],
          "wrapped" => "jobclass",
        }
      end

      it "yields" do
        expect(Labkit::Tracing::TracingUtils).to receive(:with_tracing)
                                                   .with(
                                                     hash_including(
                                                       operation_name: "sidekiq:jobclass",
                                                       tags: {
                                                         "component" => "sidekiq",
                                                         "span.kind" => "client",
                                                         "sidekiq.queue" => "jobqueue",
                                                         "sidekiq.jid" => nil,
                                                         "sidekiq.retry" => "0",
                                                         "sidekiq.args" => "1, 2, 3",
                                                         "sidekiq.wrapped" => true,
                                                       },
                                                     ),
                                                   ).and_yield(span)

        expect { |b| subject.call(worker_class, job, queue, redis_pool, &b) }.to yield_control
      end
    end

    context "when the job class is missing" do
      let(:job) { { "queue" => "jobqueue", "retry" => 0, "args" => %w[1 2 3] } }

      it "yields" do
        expect(Labkit::Tracing::TracingUtils).to receive(:with_tracing)
                                                   .with(
                                                     operation_name: "sidekiq:undefined",
                                                     tags: {
                                                       "component" => "sidekiq",
                                                       "span.kind" => "client",
                                                       "sidekiq.queue" => "jobqueue",
                                                       "sidekiq.jid" => nil,
                                                       "sidekiq.retry" => "0",
                                                       "sidekiq.args" => "1, 2, 3",
                                                       "sidekiq.wrapped" => false,
                                                     },
                                                   ).and_yield(span)

        expect { |b| subject.call(worker_class, job, queue, redis_pool, &b) }.to yield_control
      end
    end

    context "when the job is scheduled in the future" do
      let(:job) do
        {
          "class" => "jobclass",
          "queue" => "jobqueue",
          "retry" => 0,
          "args" => %w[1 2 3],
          "at" => 1_234_567_890.123,
        }
      end

      it "yields" do
        expect(Labkit::Tracing::TracingUtils).to receive(:with_tracing)
                                                   .with(
                                                     hash_including(
                                                       operation_name: "sidekiq:jobclass",
                                                       tags: {
                                                         "component" => "sidekiq",
                                                         "span.kind" => "client",
                                                         "sidekiq.queue" => "jobqueue",
                                                         "sidekiq.jid" => nil,
                                                         "sidekiq.retry" => "0",
                                                         "sidekiq.args" => "1, 2, 3",
                                                         "sidekiq.wrapped" => false,
                                                         "sidekiq.at" => 1_234_567_890.123,
                                                       },
                                                     ),
                                                   ).and_yield(span)

        expect { |b| subject.call(worker_class, job, queue, redis_pool, &b) }.to yield_control
      end
    end
  end
end
+101 −4
Original line number Diff line number Diff line
@@ -3,13 +3,23 @@
describe Labkit::Middleware::Sidekiq::Tracing::Server do
  describe "#call" do
    let(:worker_class) { "test_worker_class" }
    let(:job) { { "class" => "jobclass", "queue" => "jobqueue", "retry" => 0, "args" => %w[1 2 3] } }
    let(:queue) { "test_queue" }
    let(:custom_error) { Class.new(StandardError) }
    let(:span) { OpenTracing.start_span("test", ignore_active_scope: true) }
    let(:custom_error) { Class.new(StandardError) }

    subject { described_class.new }

    it "propagates exceptions" do
      expect do
        subject.call(worker_class, { "class" => "jobclass", "queue" => "jobqueue", "retry" => 0, "args" => [] }, queue) do
          raise custom_error
        end
      end.to raise_error(custom_error)
    end

    context "when the job is scheduled directly" do
      let(:job) { { "class" => "jobclass", "queue" => "jobqueue", "retry" => 0, "args" => %w[1 2 3] } }

      it "yields" do
        expect(Labkit::Tracing::TracingUtils).to receive(:with_tracing)
                                                   .with(
@@ -22,15 +32,102 @@ describe Labkit::Middleware::Sidekiq::Tracing::Server do
                                                         "sidekiq.jid" => nil,
                                                         "sidekiq.retry" => "0",
                                                         "sidekiq.args" => "1, 2, 3",
                                                         "sidekiq.wrapped" => false,
                                                       },
                                                     ),
                                                   ).and_yield(span)

        expect { |b| subject.call(worker_class, job, queue, &b) }.to yield_control
      end
    end

    it "propagates exceptions" do
      expect { subject.call(worker_class, job, queue) { raise custom_error } }.to raise_error(custom_error)
    context "when the job is scheduled via ActiveJob" do
      let(:job) do
        {
          "class" => "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper",
          "queue" => "jobqueue",
          "retry" => 0,
          "args" => %w[1 2 3],
          "wrapped" => "jobclass",
        }
      end

      it "yields" do
        expect(Labkit::Tracing::TracingUtils).to receive(:with_tracing)
                                                   .with(
                                                     hash_including(
                                                       operation_name: "sidekiq:jobclass",
                                                       tags: {
                                                         "component" => "sidekiq",
                                                         "span.kind" => "server",
                                                         "sidekiq.queue" => "jobqueue",
                                                         "sidekiq.jid" => nil,
                                                         "sidekiq.retry" => "0",
                                                         "sidekiq.args" => "1, 2, 3",
                                                         "sidekiq.wrapped" => true,
                                                       },
                                                     ),
                                                   ).and_yield(span)

        expect { |b| subject.call(worker_class, job, queue, &b) }.to yield_control
      end
    end

    context "when the job class is missing" do
      let(:job) { { "queue" => "jobqueue", "retry" => 0, "args" => %w[1 2 3] } }

      it "yields" do
        expect(Labkit::Tracing::TracingUtils).to receive(:with_tracing)
                                                   .with(
                                                     hash_including(
                                                       operation_name: "sidekiq:undefined",
                                                       tags: {
                                                         "component" => "sidekiq",
                                                         "span.kind" => "server",
                                                         "sidekiq.queue" => "jobqueue",
                                                         "sidekiq.jid" => nil,
                                                         "sidekiq.retry" => "0",
                                                         "sidekiq.args" => "1, 2, 3",
                                                         "sidekiq.wrapped" => false,
                                                       },
                                                     ),
                                                   ).and_yield(span)

        expect { |b| subject.call(worker_class, job, queue, &b) }.to yield_control
      end
    end

    context "when the job is scheduled in the future" do
      let(:job) do
        {
          "class" => "jobclass",
          "queue" => "jobqueue",
          "retry" => 0,
          "args" => %w[1 2 3],
          "at" => 1_234_567_890.123,
        }
      end

      it "yields" do
        expect(Labkit::Tracing::TracingUtils).to receive(:with_tracing)
                                                   .with(
                                                     hash_including(
                                                       operation_name: "sidekiq:jobclass",
                                                       tags: {
                                                         "component" => "sidekiq",
                                                         "span.kind" => "server",
                                                         "sidekiq.queue" => "jobqueue",
                                                         "sidekiq.jid" => nil,
                                                         "sidekiq.retry" => "0",
                                                         "sidekiq.args" => "1, 2, 3",
                                                         "sidekiq.wrapped" => false,
                                                         "sidekiq.at" => 1_234_567_890.123,
                                                       },
                                                     ),
                                                   ).and_yield(span)

        expect { |b| subject.call(worker_class, job, queue, &b) }.to yield_control
      end
    end
  end
end