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.025';
3             # ABSTRACT: A tiny Prometheus client with a shared database behind it
4              
5 18     18   1307080 use warnings;
  18         226  
  18         680  
6 18     18   116 use strict;
  18         38  
  18         546  
7              
8 18     18   8607 use Prometheus::Tiny 0.009;
  18         29994  
  18         595  
9 18     18   8323 use parent 'Prometheus::Tiny';
  18         5550  
  18         113  
10              
11 18     18   13267 use Hash::SharedMem qw(shash_open shash_get shash_set shash_cset shash_keys_array shash_group_get_hash);
  18         54078  
  18         2041  
12 18     18   13635 use JSON::XS qw(encode_json decode_json);
  18         134200  
  18         1507  
13 18     18   14456 use File::Temp qw(tempdir);
  18         360583  
  18         1515  
14 18     18   169 use File::Path qw(rmtree);
  18         41  
  18         808  
15 18     18   117 use Carp qw(croak);
  18         43  
  18         22800  
16              
17             sub new {
18 53     53 1 33256 my ($class, %args) = @_;
19              
20 53 100       220 if (exists $args{cache_args}) {
21 1         22 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         131 my $filename = delete $args{filename};
28 52   50     290 my $init_file = delete $args{init_file} || 0;
29              
30 52         311 my $self = $class->SUPER::new(%args);
31              
32 52 100       719 if ($filename) {
33 5 50       15 rmtree($filename) if $init_file;
34             }
35             else {
36 47         207 $filename = tempdir('pts-XXXXXXXX', TMPDIR => 1, CLEANUP => 1);
37             }
38              
39 52         61897 $self->{_shash} = shash_open($filename, 'rwc');
40              
41 52         633 return $self;
42             }
43              
44             sub set {
45 65     65 1 5211 my ($self, $name, $value, $labels, $timestamp) = @_;
46              
47 65         303 my $key = join('-', 'k', $name, $self->_format_labels($labels));
48 65         7907 shash_set($self->{_shash}, $key, encode_json([$value, $timestamp]));
49              
50 65         348 return;
51             }
52              
53             sub add {
54 136     136 1 2883 my ($self, $name, $diff, $labels) = @_;
55              
56 136         374 my $key = join('-', 'k', $name, $self->_format_labels($labels));
57              
58 136         2675 my ($ov, $nv);
59              
60             do {
61 136         372 $ov = shash_get($self->{_shash}, $key);
62 136 100       334 if ($ov) {
63 87         279 my $ar = decode_json($ov);
64 87         204 $ar->[0] += $diff;
65 87         586 $nv = encode_json($ar);
66             }
67             else {
68 49         2518 $nv = encode_json([$diff]);
69             }
70 136         225 } until shash_cset($self->{_shash}, $key, $ov, $nv);
71              
72 136         412 return;
73             }
74              
75             sub clear {
76 1     1 1 886 my ($self, $name) = @_;
77              
78 1         3 for my $key (grep { substr($_, 0, 1) eq 'k' } @{shash_keys_array($self->{_shash})}) {
  4         12  
  1         7  
79 2         7 shash_set($self->{_shash}, $key, undef);
80             }
81              
82 1         3 return;
83             }
84              
85             sub declare {
86 29     29 1 7961 my ($self, $name, %meta) = @_;
87              
88 29         89 my $key = join('-', 'm', $name);
89 29         180 my $value = encode_json(\%meta);
90              
91 29 100       3110 return if shash_cset($self->{_shash}, $key, undef, $value);
92              
93 13         88 my $old = decode_json(shash_get($self->{_shash}, $key));
94              
95 13 100 100     192 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         131 croak "redeclaration of '$name' with mismatched meta";
116             }
117              
118 3         19 return;
119             }
120              
121             sub histogram_observe {
122 9     9 1 128 my $self = shift;
123 9         26 my ($name) = @_;
124              
125 9         27 my $key = join('-', 'm', $name);
126              
127 9   100     87 $self->{meta}{$name} = decode_json(shash_get($self->{_shash}, $key) || '{}');
128              
129 9         48 return $self->SUPER::histogram_observe(@_);
130             }
131              
132             sub enum_set {
133 2     2 1 21 my $self = shift;
134 2         7 my ($name) = @_;
135              
136 2         7 my $key = join('-', 'm', $name);
137              
138 2   50     25 $self->{meta}{$name} = decode_json(shash_get($self->{_shash}, $key) || '{}');
139              
140 2         16 return $self->SUPER::enum_set(@_);
141             }
142              
143             sub format {
144 53     53 1 260665 my $self = shift;
145              
146 53         107 my (%metrics, %meta);
147              
148 53         434 my $hash = shash_group_get_hash($self->{_shash});
149 53         350 while ( my ($k, $v) = each %$hash ) {
150 130         437 my ($t, $name, $fmt) = split '-', $k, 3;
151 130 100       333 if ($t eq 'k') {
152 112         734 $metrics{$name}{$fmt} = decode_json($v);
153             }
154             else {
155 18         132 $meta{$name} = decode_json($v);
156             }
157             }
158 53         179 $self->{metrics} = \%metrics;
159 53         132 $self->{meta} = \%meta;
160              
161 53         297 return $self->SUPER::format(@_);
162             }
163              
164             1;
165              
166             __END__