Skip to content

Commit c8a9906

Browse files
committed
Refactor config validation
Move validation to a separate module and use a transform to call those methods. Remove ratio validation checks and fallbacks in Transaction, TraceContext, and DistributedTracing.
1 parent 916a61c commit c8a9906

File tree

6 files changed

+387
-38
lines changed

6 files changed

+387
-38
lines changed

lib/new_relic/agent/configuration/default_source.rb

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
require 'forwardable'
66
require_relative '../../constants'
7+
require_relative 'sampler_config_validator'
78

89
module NewRelic
910
module Agent
@@ -1457,24 +1458,36 @@ def self.convert_to_constant_list(raw_value)
14571458
:default => 'default',
14581459
:public => true,
14591460
:type => String,
1460-
:allowed_from_server => true,
1461+
:allowed_from_server => false,
14611462
:allowlist => %w[default adaptive always_on always_off trace_id_ratio_based],
1463+
:transform => SamplerConfigValidator.validate_sampler_strategy_with_ratio(
1464+
:'distributed_tracing.sampler.root',
1465+
:'distributed_tracing.sampler.root.trace_id_ratio_based.ratio'
1466+
),
14621467
:description => 'This setting controls the behavior of transaction sampling for transactions without a remote parent, traces that originate within this instance of the New Relic agent. Available values are `default`, `adaptive`, `always_on`, `always_off`, and `trace_id_ratio_based`. At this time `default` and `adaptive` are the same.'
14631468
},
14641469
:'distributed_tracing.sampler.remote_parent_sampled' => {
14651470
:default => 'default',
14661471
:public => true,
14671472
:type => String,
1468-
:allowed_from_server => true,
1473+
:allowed_from_server => false,
14691474
:allowlist => %w[default adaptive always_on always_off trace_id_ratio_based],
1475+
:transform => SamplerConfigValidator.validate_sampler_strategy_with_ratio(
1476+
:'distributed_tracing.sampler.remote_parent_sampled',
1477+
:'distributed_tracing.sampler.remote_parent_sampled.trace_id_ratio_based.ratio'
1478+
),
14701479
:description => 'This setting controls the behavior of transaction sampling when a remote parent is sampled. Available values are `default`, `adaptive`, `always_on`, `always_off`, and `trace_id_ratio_based`. At this time `default` and `adaptive` are the same.'
14711480
},
14721481
:'distributed_tracing.sampler.remote_parent_not_sampled' => {
14731482
:default => 'default',
14741483
:public => true,
14751484
:type => String,
1476-
:allowed_from_server => true,
1485+
:allowed_from_server => false,
14771486
:allowlist => %w[default adaptive always_on always_off trace_id_ratio_based],
1487+
:transform => SamplerConfigValidator.validate_sampler_strategy_with_ratio(
1488+
:'distributed_tracing.sampler.remote_parent_not_sampled',
1489+
:'distributed_tracing.sampler.remote_parent_not_sampled.trace_id_ratio_based.ratio'
1490+
),
14781491
:description => 'This setting controls the behavior of transaction sampling when a remote parent is not sampled. Available values are `default`, `adaptive`, `always_on`, `always_off`, and `trace_id_ratio_based`. At this time `default` and `adaptive` are the same.'
14791492
},
14801493
:'distributed_tracing.sampler.root.trace_id_ratio_based.ratio' => {
@@ -1483,6 +1496,7 @@ def self.convert_to_constant_list(raw_value)
14831496
:type => Float,
14841497
:allow_nil => true,
14851498
:allowed_from_server => false,
1499+
:transform => SamplerConfigValidator.method(:validate_sampling_ratio),
14861500
:description => 'The ratio used for the trace_id_ratio_based sampling decision for the root sampler. This must be a float between 0.0 and 1.0. If you provide an invalid value, the sampler will not use the trace_id_ratio_based sampler and will return to the default behavior. If you do not provide a value, the sampler will not use the trace_id_ratio_based_sampler and fall back to the default sampler.'
14871501
},
14881502
:'distributed_tracing.sampler.remote_parent_sampled.trace_id_ratio_based.ratio' => {
@@ -1491,6 +1505,7 @@ def self.convert_to_constant_list(raw_value)
14911505
:type => Float,
14921506
:allow_nil => true,
14931507
:allowed_from_server => false,
1508+
:transform => SamplerConfigValidator.method(:validate_sampling_ratio),
14941509
:description => 'The ratio used for the trace_id_ratio_based sampling decision for the remote parent sampled sampler. This must be a float between 0.0 and 1.0. If you provide an invalid value, the sampler will not use the trace_id_ratio_based sampler and will return to the default behavior. If you do not provide a value, the sampler will not use the trace_id_ratio_based_sampler and fall back to the default sampler.'
14951510
},
14961511
:'distributed_tracing.sampler.remote_parent_not_sampled.trace_id_ratio_based.ratio' => {
@@ -1499,6 +1514,7 @@ def self.convert_to_constant_list(raw_value)
14991514
:type => Float,
15001515
:allow_nil => true,
15011516
:allowed_from_server => false,
1517+
:transform => SamplerConfigValidator.method(:validate_sampling_ratio),
15021518
:description => 'The ratio used for the trace_id_ratio_based sampling decision for the remote parent not sampled sampler. This must be a float between 0.0 and 1.0. If you provide an invalid value or do not provide a value, the sampler will not use the trace_id_ratio_based_sampler and fall back to the default sampler.'
15031519
},
15041520
# Elasticsearch
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# This file is distributed under New Relic's license terms.
2+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3+
# frozen_string_literal: true
4+
5+
module NewRelic
6+
module Agent
7+
module Configuration
8+
# Handles validation for the distributed tracing sampler configs
9+
# Focuses on validating the trace id ratio based ratios
10+
module SamplerConfigValidator
11+
@sampler_strategy_warnings = {}
12+
13+
class << self
14+
def validate_sampling_ratio(ratio)
15+
return nil if ratio.nil?
16+
17+
unless valid_ratio?(ratio)
18+
return nil
19+
end
20+
21+
ratio
22+
end
23+
24+
def validate_sampler_strategy_with_ratio(strategy_key, ratio_key)
25+
proc do |strategy|
26+
next strategy unless strategy == 'trace_id_ratio_based'
27+
28+
ratio = NewRelic::Agent.config[ratio_key]
29+
30+
if valid_ratio?(ratio)
31+
next strategy
32+
end
33+
34+
unless @sampler_strategy_warnings[strategy_key]
35+
NewRelic::Agent.logger.warn(
36+
"Invalid or missing ratio for #{ratio_key} (value: #{ratio.inspect}). " \
37+
"Falling back to 'default' for #{strategy_key}."
38+
)
39+
40+
@sampler_strategy_warnings[strategy_key] = true
41+
end
42+
43+
'default'
44+
end
45+
end
46+
47+
def valid_ratio?(ratio)
48+
ratio.is_a?(Float) && (0.0..1.0).cover?(ratio)
49+
end
50+
51+
def reset_warnings!
52+
@sampler_strategy_warnings = {}
53+
end
54+
end
55+
end
56+
end
57+
end
58+
end

lib/new_relic/agent/transaction.rb

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -303,24 +303,16 @@ def sampled?
303303
false
304304
when 'trace_id_ratio_based'
305305
ratio = NewRelic::Agent.config[:'distributed_tracing.sampler.root.trace_id_ratio_based.ratio']
306-
if valid_ratio?(ratio)
307-
upper_bound = (ratio * (2**64 - 1)).ceil
308-
ratio == 1.0 || trace_id[8, 8].unpack1('Q>') < upper_bound
309-
else
310-
NewRelic::Agent.instance.adaptive_sampler.sampled?
311-
end
306+
upper_bound = (ratio * (2**64 - 1)).ceil
307+
308+
ratio == 1.0 || trace_id[8, 8].unpack1('Q>') < upper_bound
312309
when 'adaptive'
313310
NewRelic::Agent.instance.adaptive_sampler.sampled?
314311
end
315312
end
316313
@sampled
317314
end
318315

319-
def valid_ratio?(ratio)
320-
# refactor, this should be validated earlier and default already selected
321-
ratio.is_a?(Float) && (0.0..1.0).cover?(ratio)
322-
end
323-
324316
def trace_id
325317
@trace_id ||= NewRelic::Agent::GuidGenerator.generate_guid(32)
326318
end

lib/new_relic/agent/transaction/distributed_tracing.rb

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -196,19 +196,15 @@ def set_priority_and_sampled_newrelic_header(sampler, ratio, payload)
196196
transaction.sampled = false
197197
transaction.priority = 0
198198
when 'trace_id_ratio_based'
199-
if ratio.is_a?(Float) && (0.0..1.0).cover?(ratio)
200-
upper_bound = (ratio * (2**64 - 1)).ceil
201-
sampled = ratio == 1.0 || trace_id[8, 8].unpack1('Q>') < upper_bound
202-
203-
if sampled
204-
transaction.sampled = true
205-
transaction.priority = 2.0
206-
else
207-
transaction.sampled = false
208-
transaction.priority = 0
209-
end
199+
upper_bound = (ratio * (2**64 - 1)).ceil
200+
sampled = ratio == 1.0 || trace_id[8, 8].unpack1('Q>') < upper_bound
201+
202+
if sampled
203+
transaction.sampled = true
204+
transaction.priority = 2.0
210205
else
211-
use_nr_tracestate_sampled(payload)
206+
transaction.sampled = false
207+
transaction.priority = 0
212208
end
213209
when 'adaptive'
214210
use_nr_tracestate_sampled(payload)

lib/new_relic/agent/transaction/trace_context.rb

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -190,19 +190,15 @@ def set_priority_and_sampled(sampler, ratio, payload)
190190
transaction.sampled = false
191191
transaction.priority = 0
192192
when 'trace_id_ratio_based'
193-
if ratio.is_a?(Float) && (0.0..1.0).cover?(ratio)
194-
upper_bound = (ratio * (2**64 - 1)).ceil
195-
sampled = ratio == 1.0 || trace_id[8, 8].unpack1('Q>') < upper_bound
196-
197-
if sampled
198-
transaction.sampled = true
199-
transaction.priority = 2.0
200-
else
201-
transaction.sampled = false
202-
transaction.priority = 0
203-
end
193+
upper_bound = (ratio * (2**64 - 1)).ceil
194+
sampled = ratio == 1.0 || trace_id[8, 8].unpack1('Q>') < upper_bound
195+
196+
if sampled
197+
transaction.sampled = true
198+
transaction.priority = 2.0
204199
else
205-
use_nr_tracestate_sampled(payload)
200+
transaction.sampled = false
201+
transaction.priority = 0
206202
end
207203
when 'adaptive'
208204
use_nr_tracestate_sampled(payload)

0 commit comments

Comments
 (0)