Skip to content

Commit 56d21c1

Browse files
committed
feat: support context propagation through links
1 parent 56ff830 commit 56d21c1

File tree

4 files changed

+67
-3
lines changed

4 files changed

+67
-3
lines changed

instrumentation/rack/lib/opentelemetry/instrumentation/rack/instrumentation.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base
2626
option :record_frontend_span, default: false, validate: :boolean
2727
option :untraced_endpoints, default: [], validate: :array
2828
option :url_quantization, default: nil, validate: :callable
29+
option :propagate_with_link, default: nil, validate: :callable
2930
option :untraced_requests, default: nil, validate: :callable
3031
option :response_propagators, default: [], validate: :array
3132
# This option is only valid for applications using Rack 2.0 or greater

instrumentation/rack/lib/opentelemetry/instrumentation/rack/middlewares/event_handler.rb

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,15 @@ def on_start(request, _)
5555
return if untraced_request?(request.env)
5656

5757
parent_context = extract_remote_context(request)
58-
span = create_span(parent_context, request)
58+
links = nil
59+
60+
fn = propagate_with_link
61+
if fn&.call(request.env)
62+
links = prepare_span_links(parent_context)
63+
parent_context = OpenTelemetry::Context.empty
64+
end
65+
66+
span = create_span(parent_context, request, links)
5967
request.env[TOKENS_KEY] = register_current_span(span)
6068
rescue StandardError => e
6169
OpenTelemetry.handle_error(exception: e)
@@ -224,6 +232,10 @@ def url_quantization
224232
config[:url_quantization]
225233
end
226234

235+
def propagate_with_link
236+
config[:propagate_with_link]
237+
end
238+
227239
def response_propagators
228240
config[:response_propagators]
229241
end
@@ -253,17 +265,23 @@ def register_current_span(span)
253265
contexts.map { |context| OpenTelemetry::Context.attach(context) }
254266
end
255267

256-
def create_span(parent_context, request)
268+
def create_span(parent_context, request, links)
257269
span = tracer.start_span(
258270
create_request_span_name(request),
259271
with_parent: parent_context,
260272
kind: :server,
261-
attributes: request_span_attributes(request.env)
273+
attributes: request_span_attributes(request.env),
274+
links: links
262275
)
263276
request_start_time = OpenTelemetry::Instrumentation::Rack::Util::QueueTime.get_request_start(request.env)
264277
span.add_event('http.proxy.request.started', timestamp: request_start_time) unless request_start_time.nil?
265278
span
266279
end
280+
281+
def prepare_span_links(ctx)
282+
span_context = OpenTelemetry::Trace.current_span(ctx).context
283+
span_context.valid? ? [OpenTelemetry::Trace::Link.new(span_context)] : []
284+
end
267285
end
268286
end
269287
end

instrumentation/rack/test/opentelemetry/instrumentation/rack/instrumentation_test.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
_(instrumentation.config[:record_frontend_span]).must_equal false
3131
_(instrumentation.config[:untraced_endpoints]).must_be_empty
3232
_(instrumentation.config[:url_quantization]).must_be_nil
33+
_(instrumentation.config[:propagate_with_link]).must_be_nil
3334
_(instrumentation.config[:untraced_requests]).must_be_nil
3435
_(instrumentation.config[:response_propagators]).must_be_empty
3536
_(instrumentation.config[:use_rack_events]).must_equal true

instrumentation/rack/test/opentelemetry/instrumentation/rack/middlewares/event_handler_test.rb

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
allowed_request_headers: allowed_request_headers,
2525
allowed_response_headers: allowed_response_headers,
2626
url_quantization: url_quantization,
27+
propagate_with_link: propagate_with_link,
2728
response_propagators: response_propagators,
2829
enabled: instrumentation_enabled,
2930
use_rack_events: true
@@ -51,6 +52,7 @@
5152
let(:allowed_response_headers) { nil }
5253
let(:response_propagators) { nil }
5354
let(:url_quantization) { nil }
55+
let(:propagate_with_link) { nil }
5456
let(:headers) { {} }
5557
let(:app) do
5658
Rack::Builder.new.tap do |builder|
@@ -410,4 +412,46 @@ def inject(carrier)
410412
_(proxy_event).must_be_nil
411413
end
412414
end
415+
416+
describe 'link propagation' do
417+
describe 'without link propagation fn' do
418+
it 'the root span has no links' do
419+
get '/url'
420+
421+
_(rack_span.name).must_equal 'HTTP GET'
422+
_(rack_span.total_recorded_links).must_equal(0)
423+
end
424+
end
425+
426+
describe 'with link propagation fn that returns false' do
427+
let(:propagate_with_link) do
428+
->(_env) { false }
429+
end
430+
431+
it 'has no links' do
432+
get '/url'
433+
434+
_(rack_span.name).must_equal 'HTTP GET'
435+
_(rack_span.total_recorded_links).must_equal(0)
436+
end
437+
end
438+
439+
describe 'with link propagation fn that returns true' do
440+
let(:propagate_with_link) do
441+
->(env) { env['PATH_INFO'].start_with?('/url') }
442+
end
443+
444+
it 'has links' do
445+
trace_id = '618c54694e838292271da0ba122547e9'
446+
span_id = 'd408cc622ee29ce0'
447+
header 'traceparent', "00-#{trace_id}-#{span_id}-01"
448+
get '/url'
449+
450+
_(rack_span.name).must_equal 'HTTP GET'
451+
_(rack_span.total_recorded_links).must_equal(1)
452+
_(rack_span.links[0].span_context.trace_id.unpack1('H*')).must_equal(trace_id)
453+
_(rack_span.links[0].span_context.span_id.unpack1('H*')).must_equal(span_id)
454+
end
455+
end
456+
end
413457
end

0 commit comments

Comments
 (0)