Skip to content

Commit be3c37f

Browse files
committed
fix(tracing): start the request transaction with the propagation context's span_id
Logs emitted before CaptureExceptions runs carry the propagation context's span_id. Reuse it for the request's transaction, so those logs point at the transaction's span.
1 parent 06d248f commit be3c37f

6 files changed

Lines changed: 38 additions & 2 deletions

File tree

‎sentry-rails/spec/sentry/rails/capture_context_spec.rb‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,25 @@
33
require "spec_helper"
44

55
RSpec.describe Sentry::Rails::CaptureContext do
6-
# Records the current scope's trace_id every time it's called, so specs can
6+
# Records the current scope's trace context every time it's called, so specs can
77
# compare what a piece of middleware would see at different points in the stack.
88
class CaptureContextSpecProbe
99
def self.captured_trace_ids
1010
@captured_trace_ids ||= []
1111
end
1212

13+
def self.captured_span_ids
14+
@captured_span_ids ||= []
15+
end
16+
1317
def initialize(app)
1418
@app = app
1519
end
1620

1721
def call(env)
18-
self.class.captured_trace_ids << Sentry.get_current_scope.get_trace_context[:trace_id]
22+
trace_context = Sentry.get_current_scope.get_trace_context
23+
self.class.captured_trace_ids << trace_context[:trace_id]
24+
self.class.captured_span_ids << trace_context[:span_id]
1925
@app.call(env)
2026
end
2127
end
@@ -88,6 +94,7 @@ def propagation_context_in_app(env)
8894
context "when composed with CaptureExceptions", type: :request do
8995
before do
9096
CaptureContextSpecProbe.captured_trace_ids.clear
97+
CaptureContextSpecProbe.captured_span_ids.clear
9198
end
9299

93100
context "without tracing enabled" do
@@ -125,6 +132,15 @@ def propagation_context_in_app(env)
125132
get "/world"
126133
end
127134

135+
it "points a span_id captured before CaptureExceptions at the started transaction" do
136+
get "/world"
137+
138+
transaction = transport.events.last
139+
early_span_id = CaptureContextSpecProbe.captured_span_ids.first
140+
141+
expect(early_span_id).to eq(transaction.contexts.dig(:trace, :span_id))
142+
end
143+
128144
it "keeps the same trace_id from before CaptureExceptions through the started transaction" do
129145
get "/world"
130146

‎sentry-ruby/lib/sentry/propagation_context.rb‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ def initialize(scope, env = nil)
165165
def transaction_options
166166
{
167167
trace_id: trace_id,
168+
span_id: span_id,
168169
parent_span_id: parent_span_id,
169170
parent_sampled: parent_sampled,
170171
baggage: baggage,

‎sentry-ruby/spec/sentry/propagation_context_spec.rb‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
it "returns the options for continuing a fresh context" do
110110
expect(subject.transaction_options).to eq({
111111
trace_id: subject.trace_id,
112+
span_id: subject.span_id,
112113
parent_span_id: nil,
113114
parent_sampled: nil,
114115
baggage: nil,
@@ -125,6 +126,7 @@
125126

126127
expect(context.transaction_options).to eq({
127128
trace_id: "771a43a4192642f0b136d5159a501700",
129+
span_id: context.span_id,
128130
parent_span_id: "7c51afd529da4a2a",
129131
parent_sampled: true,
130132
baggage: context.baggage,

‎sentry-ruby/spec/sentry/rack/capture_exceptions_spec.rb‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ def propagation_context_in_app(stack_env)
138138

139139
expect(transaction.type).to eq("transaction")
140140
expect(transaction.contexts.dig(:trace, :trace_id)).to eq(context_in_app.trace_id)
141+
expect(transaction.contexts.dig(:trace, :span_id)).to eq(context_in_app.span_id)
141142
expect(transaction.contexts.dig(:trace, :parent_span_id)).to be_nil
142143
end
143144

@@ -151,6 +152,7 @@ def propagation_context_in_app(stack_env)
151152

152153
expect(transaction.contexts.dig(:trace, :trace_id)).to eq(external_transaction.trace_id)
153154
expect(transaction.contexts.dig(:trace, :parent_span_id)).to eq(external_transaction.span_id)
155+
expect(transaction.contexts.dig(:trace, :span_id)).to eq(context_in_app.span_id)
154156
end
155157
end
156158
end

‎sentry-ruby/spec/sentry_spec.rb‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,14 @@
11961196
expect(transaction.baggage.mutable).to eq(false)
11971197
end
11981198

1199+
it "gives the Transaction the propagation context's span_id" do
1200+
Sentry.configuration.traces_sample_rate = 1.0
1201+
1202+
transaction = described_class.continue_trace(env, name: "foobar")
1203+
1204+
expect(transaction.span_id).to eq(Sentry.get_current_scope.propagation_context.span_id)
1205+
end
1206+
11991207
describe "sample_rand propagation" do
12001208
before do
12011209
Sentry.configuration.traces_sample_rate = 1.0

‎spec/features/trace_context_spec.rb‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ def request_transaction
1818
.to eq(request_transaction.dig("contexts", "trace", "trace_id"))
1919
end
2020

21+
it "points a log emitted before CaptureExceptions at the transaction's span" do
22+
without_trace_propagation { make_request("/trace_context") }
23+
24+
expect(early_middleware_logs.first["span_id"])
25+
.to eq(request_transaction.dig("contexts", "trace", "span_id"))
26+
end
27+
2128
it "continues an incoming distributed trace in a log emitted before CaptureExceptions" do
2229
incoming_trace_id = propagated_trace_id
2330

0 commit comments

Comments
 (0)