Skip to content

Commit f3bf59c

Browse files
committed
Add parent_sampled_rate to sampling context
1 parent 2915319 commit f3bf59c

File tree

4 files changed

+409
-1
lines changed

4 files changed

+409
-1
lines changed

sentry-ruby/lib/sentry/hub.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ def start_transaction(transaction: nil, custom_sampling_context: {}, instrumente
120120

121121
sampling_context = {
122122
transaction_context: transaction.to_hash,
123-
parent_sampled: transaction.parent_sampled
123+
parent_sampled: transaction.parent_sampled,
124+
parent_sample_rate: transaction.parent_sample_rate
124125
}
125126

126127
sampling_context.merge!(custom_sampling_context)
@@ -357,6 +358,7 @@ def continue_trace(env, **options)
357358
parent_span_id: propagation_context.parent_span_id,
358359
parent_sampled: propagation_context.parent_sampled,
359360
baggage: propagation_context.baggage,
361+
sample_rand: propagation_context.sample_rand,
360362
**options
361363
)
362364
end

sentry-ruby/spec/sentry/hub_spec.rb

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,4 +641,110 @@
641641
expect(transport.events.count).to eq(0)
642642
end
643643
end
644+
645+
describe "#continue_trace" do
646+
before do
647+
configuration.traces_sample_rate = 1.0
648+
end
649+
650+
context "without incoming sentry trace" do
651+
let(:env) { { "HTTP_FOO" => "bar" } }
652+
653+
it "returns nil" do
654+
expect(subject.continue_trace(env)).to be_nil
655+
end
656+
657+
it "generates new propagation context on scope" do
658+
subject.continue_trace(env)
659+
660+
propagation_context = subject.current_scope.propagation_context
661+
expect(propagation_context.incoming_trace).to be false
662+
end
663+
end
664+
665+
context "with incoming sentry trace" do
666+
context "with sample_rand in baggage" do
667+
let(:env) do
668+
{
669+
"HTTP_SENTRY_TRACE" => "771a43a4192642f0b136d5159a501700-7c51afd529da4a2a-1",
670+
"HTTP_BAGGAGE" => "sentry-trace_id=771a43a4192642f0b136d5159a501700,sentry-sample_rand=0.123456"
671+
}
672+
end
673+
674+
it "creates Transaction with sample_rand from PropagationContext" do
675+
transaction = subject.continue_trace(env, name: "test_transaction")
676+
677+
expect(transaction).to be_a(Sentry::Transaction)
678+
679+
propagation_context = subject.current_scope.propagation_context
680+
681+
expect(propagation_context.sample_rand).to eq(0.123456)
682+
expect(transaction.sample_rand).to eq(0.123456)
683+
end
684+
685+
it "creates Transaction with correct trace properties" do
686+
transaction = subject.continue_trace(env, name: "test_transaction")
687+
688+
expect(transaction.trace_id).to eq("771a43a4192642f0b136d5159a501700")
689+
expect(transaction.parent_span_id).to eq("7c51afd529da4a2a")
690+
expect(transaction.parent_sampled).to be true
691+
end
692+
693+
it "preserves baggage in Transaction" do
694+
transaction = subject.continue_trace(env, name: "test_transaction")
695+
696+
baggage = transaction.get_baggage
697+
698+
expect(baggage.items["trace_id"]).to eq("771a43a4192642f0b136d5159a501700")
699+
expect(baggage.items["sample_rand"]).to eq("0.123456")
700+
end
701+
end
702+
703+
context "without sample_rand in baggage" do
704+
let(:env) do
705+
{
706+
"HTTP_SENTRY_TRACE" => "771a43a4192642f0b136d5159a501700-7c51afd529da4a2a-1",
707+
"HTTP_BAGGAGE" => "sentry-trace_id=771a43a4192642f0b136d5159a501700"
708+
}
709+
end
710+
711+
it "creates Transaction with deterministic sample_rand" do
712+
transaction = subject.continue_trace(env, name: "test_transaction")
713+
714+
propagation_context = subject.current_scope.propagation_context
715+
716+
expect(transaction.sample_rand).to eq(propagation_context.sample_rand)
717+
718+
expected = Sentry::Utils::SampleRand.generate_from_trace_id("771a43a4192642f0b136d5159a501700")
719+
720+
expect(transaction.sample_rand).to eq(expected)
721+
end
722+
end
723+
724+
context "with tracing disabled" do
725+
before do
726+
configuration.traces_sample_rate = nil
727+
end
728+
729+
let(:env) do
730+
{
731+
"HTTP_SENTRY_TRACE" => "771a43a4192642f0b136d5159a501700-7c51afd529da4a2a-1",
732+
"HTTP_BAGGAGE" => "sentry-trace_id=771a43a4192642f0b136d5159a501700,sentry-sample_rand=0.123456"
733+
}
734+
end
735+
736+
it "returns nil even with valid incoming trace" do
737+
expect(subject.continue_trace(env)).to be_nil
738+
end
739+
740+
it "still generates propagation context on scope" do
741+
subject.continue_trace(env)
742+
743+
propagation_context = subject.current_scope.propagation_context
744+
expect(propagation_context.incoming_trace).to be true
745+
expect(propagation_context.sample_rand).to eq(0.123456)
746+
end
747+
end
748+
end
749+
end
644750
end
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe "Transactions and sample rand propagation" do
4+
before do
5+
perform_basic_setup do |config|
6+
config.traces_sample_rate = 1.0
7+
end
8+
end
9+
10+
describe "sample_rand propagation" do
11+
it "uses value from the baggage" do
12+
env = {
13+
"HTTP_SENTRY_TRACE" => "771a43a4192642f0b136d5159a501700-7c51afd529da4a2a-1",
14+
"HTTP_BAGGAGE" => "sentry-trace_id=771a43a4192642f0b136d5159a501700,sentry-sample_rand=0.123456"
15+
}
16+
17+
transaction = Sentry.continue_trace(env, name: "backend_request", op: "http.server")
18+
propagation_context = Sentry.get_current_scope.propagation_context
19+
20+
expect(propagation_context.sample_rand).to eq(0.123456)
21+
expect(transaction.sample_rand).to eq(0.123456)
22+
23+
expect(transaction.sample_rand).to eq(propagation_context.sample_rand)
24+
end
25+
26+
it "generates deterministic value from trace id if there's no value in the baggage" do
27+
env = {
28+
"HTTP_SENTRY_TRACE" => "771a43a4192642f0b136d5159a501700-7c51afd529da4a2a-1",
29+
"HTTP_BAGGAGE" => "sentry-trace_id=771a43a4192642f0b136d5159a501700"
30+
}
31+
32+
transaction = Sentry.continue_trace(env, name: "backend_request", op: "http.server")
33+
propagation_context = Sentry.get_current_scope.propagation_context
34+
35+
expect(transaction.sample_rand).to eq(propagation_context.sample_rand)
36+
37+
expected = Sentry::Utils::SampleRand.generate_from_trace_id("771a43a4192642f0b136d5159a501700")
38+
39+
expect(transaction.sample_rand).to eq(expected)
40+
expect(propagation_context.sample_rand).to eq(expected)
41+
end
42+
43+
it "properly handles sampling decisions" do
44+
test_cases = [
45+
{ sample_rand: 0.1, sample_rate: 0.5, should_sample: true },
46+
{ sample_rand: 0.7, sample_rate: 0.5, should_sample: false },
47+
{ sample_rand: 0.5, sample_rate: 0.5, should_sample: false },
48+
{ sample_rand: 0.499999, sample_rate: 0.5, should_sample: true }
49+
]
50+
51+
test_cases.each do |test_case|
52+
Sentry.configuration.traces_sample_rate = test_case[:sample_rate]
53+
54+
env = {
55+
"HTTP_SENTRY_TRACE" => "771a43a4192642f0b136d5159a501700-7c51afd529da4a2a-",
56+
"HTTP_BAGGAGE" => "sentry-trace_id=771a43a4192642f0b136d5159a501700,sentry-sample_rand=#{test_case[:sample_rand]}"
57+
}
58+
59+
transaction = Sentry.continue_trace(env, name: "test")
60+
Sentry.start_transaction(transaction: transaction)
61+
62+
expect(transaction.sampled).to eq(test_case[:should_sample])
63+
end
64+
end
65+
66+
it "ensures baggage propagation includes correct sample_rand" do
67+
env = {
68+
"HTTP_SENTRY_TRACE" => "771a43a4192642f0b136d5159a501700-7c51afd529da4a2a-1",
69+
"HTTP_BAGGAGE" => "sentry-trace_id=771a43a4192642f0b136d5159a501700,sentry-sample_rand=0.654321"
70+
}
71+
72+
transaction = Sentry.continue_trace(env, name: "backend_request")
73+
baggage = transaction.get_baggage
74+
75+
expect(baggage.items["sample_rand"]).to eq("0.654321")
76+
77+
Sentry.get_current_scope.set_span(transaction)
78+
79+
headers = Sentry.get_trace_propagation_headers
80+
81+
expect(headers["baggage"]).to include("sentry-sample_rand=0.654321")
82+
end
83+
84+
it "handles edge cases and invalid sample_rand values" do
85+
env = {
86+
"HTTP_SENTRY_TRACE" => "771a43a4192642f0b136d5159a501700-7c51afd529da4a2a-1",
87+
"HTTP_BAGGAGE" => "sentry-trace_id=771a43a4192642f0b136d5159a501700,sentry-sample_rand=1.5"
88+
}
89+
90+
transaction = Sentry.continue_trace(env, name: "test")
91+
propagation_context = Sentry.get_current_scope.propagation_context
92+
93+
expected = Sentry::Utils::SampleRand.generate_from_trace_id("771a43a4192642f0b136d5159a501700")
94+
95+
expect(transaction.sample_rand).to eq(expected)
96+
expect(propagation_context.sample_rand).to eq(expected)
97+
end
98+
99+
it "works correctly with multiple sequential requests" do
100+
requests = [
101+
{ sample_rand: 0.111111, trace_id: "11111111111111111111111111111111" },
102+
{ sample_rand: 0.222222, trace_id: "22222222222222222222222222222222" },
103+
{ sample_rand: 0.333333, trace_id: "33333333333333333333333333333333" }
104+
]
105+
106+
requests.each do |request|
107+
env = {
108+
"HTTP_SENTRY_TRACE" => "#{request[:trace_id]}-7c51afd529da4a2a-1",
109+
"HTTP_BAGGAGE" => "sentry-trace_id=#{request[:trace_id]},sentry-sample_rand=#{request[:sample_rand]}"
110+
}
111+
112+
transaction = Sentry.continue_trace(env, name: "test")
113+
114+
expect(transaction.sample_rand).to eq(request[:sample_rand])
115+
expect(transaction.trace_id).to eq(request[:trace_id])
116+
end
117+
end
118+
end
119+
end

0 commit comments

Comments
 (0)