File Coverage

blib/lib/OpenTelemetry/SDK/Trace/Sampler/TraceIDRatioBased.pm
Criterion Covered Total %
statement 34 34 100.0
branch 4 4 100.0
condition n/a
subroutine 9 9 100.0
pod 2 2 100.0
total 49 49 100.0


line stmt bran cond sub pod time code
1 4     4   154219 use Object::Pad ':experimental(init_expr)';
  4         15912  
  4         28  
2             # ABSTRACT: A sampler based on the trace ID
3              
4             package OpenTelemetry::SDK::Trace::Sampler::TraceIDRatioBased;
5              
6             our $VERSION = '0.028';
7              
8 4     4   1396 use OpenTelemetry::SDK::Trace::Sampler::Result;
  4         11  
  4         581  
9              
10             class OpenTelemetry::SDK::Trace::Sampler::TraceIDRatioBased
11             :does(OpenTelemetry::SDK::Trace::Sampler)
12 1     1   569 {
  1         5  
  1         273  
13 4     4   318 use OpenTelemetry::Common ();
  4         8  
  4         183  
14 4     4   26 use Scalar::Util 'looks_like_number';
  4         7  
  4         2510  
15              
16             my $logger = OpenTelemetry::Common::internal_logger;
17              
18             field $threshold;
19             field $ratio :param = 1;
20 12     12 1 5465 field $description :reader;
  12         89  
21              
22             ADJUST {
23             unless ( looks_like_number $ratio ) {
24             $logger->warn(
25             'Ratio for TraceIDRatioBased sampler was not a number',
26             { ratio => $ratio },
27             );
28             undef $ratio;
29             }
30              
31             if ( defined $ratio && ( $ratio < 0 || $ratio > 1 ) ) {
32             $logger->warn(
33             'Ratio for TraceIDRatioBased sampler was not in 0..1 range',
34             { ratio => $ratio },
35             );
36             undef $ratio;
37             }
38              
39             $ratio //= 1;
40              
41             # Ensure ratio is a floating point number
42             # but don't lose precision
43             $description = sprintf 'TraceIDRatioBased{%s}',
44             $ratio != int $ratio
45             ? sprintf('%f', $ratio) =~ s/0+$//r
46             : sprintf('%.1f', $ratio);
47              
48             # This conversion is internal only, just for the placeholder
49             # algorithm used below. We convert this to an integer value that
50             # can be compared directly with the one derived from the Trace ID,
51             # in the range from 0 (never sample) to 2**64 (always sample)
52             $threshold = do {
53 4     4   2757 use bigfloat;
  4         19424  
  4         21  
54             # Since Math::BigFloat 1.999840 onwards, the shift operators are
55             # exclusively integer-based, so we enforce precedent here
56             ( $ratio * ( 1 << 64 ) )->bceil;
57             };
58             }
59              
60 56     56 1 44674 method should_sample (%args) {
  56         303  
  56         177  
  56         90  
61             my $trace_state = OpenTelemetry::Trace
62             ->span_from_context($args{context})
63 56         431 ->context->trace_state;
64              
65             # TODO: The specific algorithm of this sampler is still being
66             # determined. See: https://github.com/open-telemetry/opentelemetry-specification/issues/1413
67             # The algorithm implemented below is equivalent to the version
68             # used by the Ruby and Go SDKs at the time of writing.
69              
70 56 100       4163 if ($ratio) {
71 48         92 my $check = do {
72             # We don't care about uninitialised values, since those
73             # will just turn into zeroes, which is safe.
74 4     4   1031899 no warnings 'uninitialized';
  4         9  
  4         1739  
75              
76             # We drop the first 8 bytes and parse the last 8 as an
77             # unsigned 64-bit big-endian integer.
78             # The dance with N2 instead of Q> is because Q> requires
79             # 64-bit integer support on both this specific version of
80             # perl (lowercase) and the system that runs it.
81 48         281 my ( $hi, $lo ) = unpack 'x8 N2', $args{trace_id};
82 48         209 $hi << 32 | $lo;
83             };
84              
85 48 100       286 return OpenTelemetry::SDK::Trace::Sampler::Result->new(
86             decision => OpenTelemetry::SDK::Trace::Sampler::Result::RECORD_AND_SAMPLE,
87             trace_state => $trace_state,
88             ) if $check < $threshold;
89             }
90              
91 28         11446 return OpenTelemetry::SDK::Trace::Sampler::Result->new(
92             decision => OpenTelemetry::SDK::Trace::Sampler::Result::DROP,
93             trace_state => $trace_state,
94             );
95             }
96             }