Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add trace context in Sidekiq to connect request transaction and worker in the one trace #1456

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 = ElasticAPM::TraceContext.parse(
metadata: {
'traceparent' => transaction.trace_context.traceparent.to_header,
'tracestate' => transaction.trace_context.tracestate.to_header
}
)

allow_any_instance_of(ElasticAPM::Spies::SidekiqSpy::Middleware).to(
receive(:get_trace_context_from).and_return(fake_trace_context)
)

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