Skip to content

Commit fd18178

Browse files
committed
feat: add example.id attribute to RSpec spans
Record RSpec's example.id as a span attribute to provide unique identification for each test example. This is particularly valuable when examples are created dynamically (e.g., within loops), where multiple examples share the same file location but have distinct IDs.
1 parent c8d2f6a commit fd18178

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

instrumentation/rspec/lib/opentelemetry/instrumentation/rspec/formatter.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ def example_group_finished(notification)
5858
def example_started(notification)
5959
example = notification.example
6060
attributes = {
61+
'rspec.example.id' => example.id.to_s,
6162
'rspec.example.location' => example.location.to_s,
6263
'rspec.example.full_description' => example.full_description.to_s,
6364
'rspec.example.described_class' => example.metadata[:described_class].to_s

instrumentation/rspec/test/opentelemetry/instrumentation/rspec/formatter_test.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ def run_example(...)
131131
_(subject.attributes['rspec.example.location']).must_match %r{\./test/opentelemetry/instrumentation/rspec/formatter_test.rb:\d+}
132132
end
133133

134+
it 'has an id attribute' do
135+
_(subject.attributes['rspec.example.id']).must_match %r{\./test/opentelemetry/instrumentation/rspec/formatter_test.rb\[\d+:\d+\]}
136+
end
137+
134138
it 'records when the example passes' do
135139
_(subject.attributes['rspec.example.result']).must_equal 'passed'
136140
end
@@ -346,6 +350,32 @@ def run_example(...)
346350
_(subject.attributes['rspec.example.result']).must_equal 'passed'
347351
end
348352
end
353+
354+
describe 'dynamic examples with same location' do
355+
it 'have unique example.id attributes' do
356+
spans = run_rspec_with_tracing do
357+
RSpec.describe('dynamic examples') do
358+
[1, 2, 3].each do |num|
359+
example("example #{num}") { expect(num).to be_positive }
360+
end
361+
end
362+
end
363+
364+
example_spans = spans.select { |span| span.name.start_with?('example ') }
365+
_(example_spans.size).must_equal 3
366+
367+
# All examples have the same location (same line in the loop)
368+
locations = example_spans.map { |span| span.attributes['rspec.example.location'] }
369+
_(locations.uniq.size).must_equal 1
370+
371+
# But each has a unique id
372+
ids = example_spans.map { |span| span.attributes['rspec.example.id'] }
373+
_(ids.uniq.size).must_equal 3
374+
ids.each do |id|
375+
_(id).must_match %r{\./test/opentelemetry/instrumentation/rspec/formatter_test.rb\[\d+:\d+\]}
376+
end
377+
end
378+
end
349379
end
350380

351381
describe 'using a custom tracer provider' do

0 commit comments

Comments
 (0)