File Coverage

blib/lib/Prometheus/Tiny/Shared.pm
Criterion Covered Total %
statement 88 88 100.0
branch 13 14 92.8
condition 46 54 85.1
subroutine 17 17 100.0
pod 8 8 100.0
total 172 181 95.0


line stmt bran cond sub pod time code
1             package Prometheus::Tiny::Shared;
2             $Prometheus::Tiny::Shared::VERSION = '0.026';
3             # ABSTRACT: A tiny Prometheus client with a shared database behind it
4              
5 18     18   1044189 use warnings;
  18         166  
  18         551  
6 18     18   88 use strict;
  18         28  
  18         412  
7              
8 18     18   7032 use Prometheus::Tiny 0.010;
  18         26225  
  18         470  
9 18     18   6475 use parent 'Prometheus::Tiny';
  18         4434  
  18         89  
10              
11 18     18   10405 use Hash::SharedMem qw(shash_open shash_get shash_set shash_cset shash_keys_array shash_group_get_hash);
  18         43621  
  18         1504  
12 18     18   10942 use JSON::XS qw(encode_json decode_json);
  18         107138  
  18         1127  
13 18     18   11508 use File::Temp qw(tempdir);
  18         288706  
  18         1066  
14 18     18   130 use File::Path qw(rmtree);
  18         34  
  18         632  
15 18     18   87 use Carp qw(croak);
  18         34  
  18         17536  
16              
17             sub new {
18 53     53 1 26420 my ($class, %args) = @_;
19              
20 53 100       181 if (exists $args{cache_args}) {
21 1         13 croak <
22             The 'cache_args' argument to Prometheus::Tiny::Shared::new has been removed.
23             Read the docs for more info, and switch to the 'filename' argument.
24             EOF
25             }
26              
27 52         107 my $filename = delete $args{filename};
28 52   50     237 my $init_file = delete $args{init_file} || 0;
29              
30 52         249 my $self = $class->SUPER::new(%args);
31              
32 52 100       584 if ($filename) {
33 5 50       12 rmtree($filename) if $init_file;
34             }
35             else {
36 47         159 $filename = tempdir('pts-XXXXXXXX', TMPDIR => 1, CLEANUP => 1);
37             }
38              
39 52         30439 $self->{_shash} = shash_open($filename, 'rwc');
40              
41 52         511 return $self;
42             }
43              
44             sub set {
45 65     65 1 3885 my ($self, $name, $value, $labels, $timestamp) = @_;
46              
47 65         258 my $key = join('-', 'k', $name, $self->_format_labels($labels));
48 65         6781 shash_set($self->{_shash}, $key, encode_json([$value, $timestamp]));
49              
50 65         287 return;
51             }
52              
53             sub add {
54 136     136 1 2331 my ($self, $name, $diff, $labels) = @_;
55              
56 136         303 my $key = join('-', 'k', $name, $self->_format_labels($labels));
57              
58 136         2138 my ($ov, $nv);
59              
60             do {
61 136         300 $ov = shash_get($self->{_shash}, $key);
62 136 100       263 if ($ov) {
63 87         267 my $ar = decode_json($ov);
64 87         144 $ar->[0] += $diff;
65 87         446 $nv = encode_json($ar);
66             }
67             else {
68 49         2147 $nv = encode_json([$diff]);
69             }
70 136         172 } until shash_cset($self->{_shash}, $key, $ov, $nv);
71              
72 136         336 return;
73             }
74              
75             sub clear {
76 1     1 1 722 my ($self, $name) = @_;
77              
78 1         2 for my $key (grep { substr($_, 0, 1) eq 'k' } @{shash_keys_array($self->{_shash})}) {
  4         9  
  1         7  
79 2         6 shash_set($self->{_shash}, $key, undef);
80             }
81              
82 1         3 return;
83             }
84              
85             sub declare {
86 29     29 1 6258 my ($self, $name, %meta) = @_;
87              
88 29         80 my $key = join('-', 'm', $name);
89 29         143 my $value = encode_json(\%meta);
90              
91 29 100       2503 return if shash_cset($self->{_shash}, $key, undef, $value);
92              
93 13         65 my $old = decode_json(shash_get($self->{_shash}, $key));
94              
95 13 100 100     145 if (
      100        
      66        
      33        
      66        
      100        
      100        
      66        
      100        
      100        
      100        
      100        
      100        
      100        
      66        
      100        
96             ((exists $old->{type} ^ exists $meta{type}) ||
97             (exists $old->{type} && $old->{type} ne $meta{type})) ||
98             ((exists $old->{help} ^ exists $meta{help}) ||
99             (exists $old->{help} && $old->{help} ne $meta{help})) ||
100             ((exists $old->{enum} ^ exists $meta{enum}) ||
101             (exists $old->{enum} && $old->{enum} ne $meta{enum})) ||
102             ((exists $old->{buckets} ^ exists $meta{buckets}) ||
103             (exists $old->{buckets} && (
104             @{$old->{buckets}} ne @{$meta{buckets}} ||
105             grep { $old->{buckets}[$_] != $meta{buckets}[$_] } (0 .. $#{$meta{buckets}})
106             ))
107             ) ||
108             ((exists $old->{enum_values} ^ exists $meta{enum_values}) ||
109             (exists $old->{enum_values} && (
110             @{$old->{enum_values}} ne @{$meta{enum_values}} ||
111             grep { $old->{enum_values}[$_] ne $meta{enum_values}[$_] } (0 .. $#{$meta{enum_values}})
112             ))
113             )
114             ) {
115 10         106 croak "redeclaration of '$name' with mismatched meta";
116             }
117              
118 3         13 return;
119             }
120              
121             sub histogram_observe {
122 9     9 1 50 my $self = shift;
123 9         17 my ($name) = @_;
124              
125 9         16 my $key = join('-', 'm', $name);
126              
127 9   100     57 $self->{meta}{$name} = decode_json(shash_get($self->{_shash}, $key) || '{}');
128              
129 9         25 return $self->SUPER::histogram_observe(@_);
130             }
131              
132             sub enum_set {
133 2     2 1 17 my $self = shift;
134 2         6 my ($name) = @_;
135              
136 2         5 my $key = join('-', 'm', $name);
137              
138 2   50     18 $self->{meta}{$name} = decode_json(shash_get($self->{_shash}, $key) || '{}');
139              
140 2         10 return $self->SUPER::enum_set(@_);
141             }
142              
143             sub format {
144 53     53 1 229079 my $self = shift;
145              
146 53         95 my (%metrics, %meta);
147              
148 53         347 my $hash = shash_group_get_hash($self->{_shash});
149 53         274 while ( my ($k, $v) = each %$hash ) {
150 130         390 my ($t, $name, $fmt) = split '-', $k, 3;
151 130 100       270 if ($t eq 'k') {
152 112         619 $metrics{$name}{$fmt} = decode_json($v);
153             }
154             else {
155 18         104 $meta{$name} = decode_json($v);
156             }
157             }
158 53         130 $self->{metrics} = \%metrics;
159 53         111 $self->{meta} = \%meta;
160              
161 53         245 return $self->SUPER::format(@_);
162             }
163              
164             1;
165              
166             __END__