Skip to content

Commit

Permalink
Add trace context in Sidekiq to connect request transaction and worke…
Browse files Browse the repository at this point in the history
…r in the one trace
  • Loading branch information
dixent committed May 10, 2024
1 parent 186dc98 commit 9609fa1
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 1 deletion.
37 changes: 36 additions & 1 deletion lib/elastic_apm/spies/sidekiq.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class SidekiqSpy
class Middleware
def call(_worker, job, queue)
name = SidekiqSpy.name_for(job)
transaction = ElasticAPM.start_transaction(name, 'Sidekiq')
transaction = ElasticAPM.start_transaction(name, 'Sidekiq', trace_context: get_trace_context_from(job))
ElasticAPM.set_label(:queue, queue)

yield
Expand All @@ -44,6 +44,35 @@ def call(_worker, job, queue)
ensure
ElasticAPM.end_transaction
end

private

def get_trace_context_from(job)
return unless job['elastic_trace_context']

ElasticAPM::TraceContext.parse(metadata: job['elastic_trace_context'])
end
end

# @api private
class ClientMiddleware
def call(_worker_class, job, _queue, _redis_pool)
job['elastic_trace_context'] = elastic_trace_context
yield
end

private

def elastic_trace_context
return unless ElasticAPM.current_transaction

trace_context = ElasticAPM.current_transaction.trace_context

{
'traceparent' => trace_context.traceparent.to_header,
'tracestate' => trace_context.tracestate.to_header
}
end
end

def self.name_for(job)
Expand All @@ -63,6 +92,12 @@ def install_middleware
chain.add Middleware
end
end

Sidekiq.configure_client do |config|
config.server_middleware do |chain|
chain.add ClientMiddleware
end
end
end

# @api private
Expand Down
57 changes: 57 additions & 0 deletions spec/elastic_apm/spies/sidekiq_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,36 @@ def perform
expect(error.dig('exception', 'type')).to eq 'ZeroDivisionError'
end

it 'creates a transaction with trace from job' do
with_agent do
transaction = ElasticAPM.start_transaction 'Test'
ElasticAPM.end_transaction

fake_trace_context = transaction.trace_context

allow_any_instance_of(ElasticAPM::Spies::SidekiqSpy::Middleware).to receive(:get_trace_context_from).and_return(
ElasticAPM::TraceContext.parse(
metadata: {
'traceparent' => fake_trace_context.traceparent.to_header,
'tracestate' => fake_trace_context.tracestate.to_header
}
)
)

Sidekiq::Testing.inline! do
HardWorker.perform_async
end
end

wait_for transactions: 2

fake_transaction, worker_transaction = @mock_intake.transactions

expect(worker_transaction).to_not be_nil
expect(worker_transaction['trace_id']).to eq(fake_transaction['trace_id'])
expect(worker_transaction['parent_id']).to eq(fake_transaction['id'])
end

context 'ActiveJob', if: defined?(ActiveJob) do
before :all do
class ::ActiveJobbyJob < ActiveJob::Base
Expand Down Expand Up @@ -158,5 +188,32 @@ def perform
end
end
end

describe Spies::SidekiqSpy::ClientMiddleware do
before :all do
Sidekiq.configure_client do |config|
config.client_middleware do |chain|
chain.add Spies::SidekiqSpy::ClientMiddleware
end
end
end

it 'adds trace context to job' do
current_transaction =
with_agent do
ElasticAPM.with_transaction do |transaction|
HardWorker.perform_async
transaction
end
end

current_job = Sidekiq::Queues['default'].first

trace_context = current_transaction.trace_context

expect(current_job['elastic_trace_context']['traceparent']).to eq(trace_context.traceparent.to_header)
expect(current_job['elastic_trace_context']['tracestate']).to eq(trace_context.tracestate.to_header)
end
end
end
end

0 comments on commit 9609fa1

Please sign in to comment.