File Coverage

blib/lib/OpenTelemetry/Propagator/TraceContext/TraceState.pm
Criterion Covered Total %
statement 49 49 100.0
branch 8 8 100.0
condition 5 5 100.0
subroutine 11 11 100.0
pod 5 5 100.0
total 78 78 100.0


line stmt bran cond sub pod time code
1 16     16   207514 use Object::Pad;
  16         9256  
  16         154  
2             # ABSTRACT: Represents the TraceState in a W3C TraceContext
3              
4             package OpenTelemetry::Propagator::TraceContext::TraceState;
5              
6             our $VERSION = '0.033';
7              
8             class OpenTelemetry::Propagator::TraceContext::TraceState {
9 16     16   9616 use List::Util;
  16         60  
  16         1286  
10 16     16   522 use OpenTelemetry::Common ();
  16         114  
  16         33924  
11              
12             my $logger = OpenTelemetry::Common::internal_logger;
13              
14             my $MAX_MEMBERS = 32 * 2; # The member list is a flat list of pairs
15             my $VALID_KEY = qr/
16             ^
17             (?:
18             [ a-z ] [ a-z 0-9 _ * \/ - ]{0,255} # simple-key
19             | (?: # multi-tenant-key
20             [ a-z 0-9 ] [ a-z 0-9 _ * \/ - ]{0,240} # tenant-id
21             @
22             [ a-z ] [ a-z 0-9 _ * \/ - ]{0,13} # system-id
23             )
24             )
25             $
26             /xx;
27              
28             my $VALID_VALUE = qr/
29             ^
30             [ \x{20} \x{21}-\x{2B} \x{2D}-\x{3C} \x{3E}-\x{7E} ]{0,255}
31             [ \x{21}-\x{2B} \x{2D}-\x{3C} \x{3E}-\x{7E} ]
32             $
33             /xx;
34              
35             field @members;
36              
37             # Private methods
38              
39             method $init ( @new ) {
40             @members = splice @new, 0, $MAX_MEMBERS;
41             $self
42             }
43              
44             # Internal setting method: assumes parameters are validated
45             # Having this in a separate method means we can call it from an
46             # instance other than $self (eg. the one returned by the call to
47             # 'delete' in the public 'set' method)
48             method $set ( $key, $value ) {
49             unshift @members, $key => $value;
50             @members = splice @members, 0, $MAX_MEMBERS if @members > $MAX_MEMBERS;
51             $self;
52             }
53              
54             # Public interface
55              
56 13     13 1 257138 sub from_string ( $class, $string = undef ) {
  13         21  
  13         22  
  13         17  
57 13 100       44 $logger->debug('Got an undefined value instead of a string when parsing TraceState')
58             unless defined $string;
59              
60 13         89 my @members;
61 13   100     75 for ( grep $_, split ',', $string // '' ) {
62 20         119 my ( $key, $value ) = split '=', s/^\s+|\s+$//gr, 2;
63              
64 20 100 100     200 next unless $key =~ $VALID_KEY && $value =~ $VALID_VALUE;
65 18         44 push @members, $key => $value;
66             }
67              
68 13         104 $class->new->$init(@members);
69             }
70              
71 20     20 1 481 method to_string () {
  20         38  
  20         22  
72 31     31   137 join ',', List::Util::pairmap { join '=', $a, $b } @members
73 20         137 }
74              
75             # Gets the value
76 5     5 1 1252 method get ( $key ) {
  5         15  
  5         6  
  5         19  
77 5     8   42 my ( undef, $value ) = List::Util::pairfirst { $a eq $key } @members;
  8         14  
78 5         23 $value;
79             }
80              
81             # Sets a new pair, overwriting any existing one with the same key
82 9     9 1 38 method set ( $key, $value ) {
  9         25  
  9         10  
  9         26  
  9         13  
83 9 100       84 if ( $key !~ $VALID_KEY ) {
    100          
84 2         8 $logger->debugf("Invalid TraceState member key: '%s' => '%s'", $key, $value );
85 2         137 return $self;
86             }
87             elsif ( $value !~ $VALID_VALUE ) {
88 5         16 $logger->debugf("Invalid TraceState member value: '%s' => '%s'", $key, $value );
89 5         289 return $self;
90             }
91              
92 2         8 $self->delete($key)->$set( $key => $value );
93             }
94              
95             # Returns a clone of the TraceState without the deleted key
96 5     5 1 8 method delete ( $key ) {
  5         11  
  5         8  
  5         5  
97             ( ref $self )->new->$init(
98 10     10   20 List::Util::pairgrep { $a ne $key } @members
99 5         21 );
100             }
101             }