File Coverage

blib/lib/Net/Prometheus/PerlCollector.pm
Criterion Covered Total %
statement 34 34 100.0
branch 5 6 83.3
condition 1 3 33.3
subroutine 8 8 100.0
pod 0 2 0.0
total 48 53 90.5


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2018-2024 -- leonerd@leonerd.org.uk
5              
6             package Net::Prometheus::PerlCollector 0.16;
7              
8 10     10   125 use v5.20;
  10         42  
9 10     10   54 use warnings;
  10         19  
  10         655  
10              
11             BEGIN {
12 10     10   574 our $VERSION = '0.16';
13             }
14              
15 10         22 use constant HAVE_XS => defined eval {
16 10         33 require XSLoader;
17 10         6149 XSLoader::load( __PACKAGE__, our $VERSION );
18 10         975 1;
19 10     10   56 };
  10         20  
20              
21 10     10   80 use Net::Prometheus::Types qw( MetricSamples Sample );
  10         35  
  10         2145  
22              
23             our $DETAIL = 0;
24              
25             =head1 NAME
26              
27             C - obtain statistics about the perl interpreter
28              
29             =head1 SYNOPSIS
30              
31             =for highlighter language=perl
32              
33             use Net::Prometheus;
34             use Net::Prometheus::PerlCollector;
35              
36             my $client = Net::Prometheus->new;
37             $client->register( Net::Prometheus::PerlCollector->new );
38              
39             =head1 DESCRIPTION
40              
41             This module provides a class that collects metrics about the perl interpreter
42             itself.
43              
44             =head2 Metrics
45              
46             The following metrics are collected:
47              
48             =for highlighter
49              
50             =over 2
51              
52             =item * C
53              
54             An info gauge (i.e. whose value is always 1) with a C label giving
55             the perl interpreter version
56              
57             # HELP perl_info Information about the Perl interpreter
58             # TYPE perl_info gauge
59             perl_info{version="5.30.0"} 1
60              
61             =back
62              
63             If the optional XS module was compiled at build time, the following extra are
64             also reported:
65              
66             =over 2
67              
68             =item * C
69              
70             A gauge giving the number of arenas the heap is split into.
71              
72             =item * C
73              
74             A gauge giving the total number of SVs allocated on the heap.
75              
76             =back
77              
78             # HELP perl_heap_arenas Number of arenas in the Perl heap
79             # TYPE perl_heap_arenas gauge
80             perl_heap_arenas 159
81             # HELP perl_heap_svs Number of SVs in the Perl heap
82             # TYPE perl_heap_svs gauge
83             perl_heap_svs 26732
84              
85             Note that the way these metrics are collected requires counting them all every
86             time. While this code is relatively efficient, it is still a linear scan, and
87             may itself cause some slowdown of the process at the time it is collected, if
88             the heap has grown very large, containing a great number of SVs.
89              
90             Extra detail can be obtained about the types of heap objects by setting
91              
92             =for highlighter language=perl
93              
94             $Net::Prometheus::PerlCollector::DETAIL = 1;
95              
96             This will be slightly more expensive to count, but will yield in addition a
97             detailed breakdown by object type.
98              
99             =for highlighter
100              
101             # HELP perl_heap_svs_by_type Number of SVs classified by type
102             # TYPE perl_heap_svs_by_type gauge
103             perl_heap_svs_by_type{type="ARRAY"} 2919
104             perl_heap_svs_by_type{type="CODE"} 1735
105             perl_heap_svs_by_type{type="GLOB"} 2647
106             perl_heap_svs_by_type{type="HASH"} 470
107             perl_heap_svs_by_type{type="INVLIST"} 68
108             perl_heap_svs_by_type{type="IO"} 12
109             perl_heap_svs_by_type{type="NULL"} 8752
110             perl_heap_svs_by_type{type="REGEXP"} 171
111             perl_heap_svs_by_type{type="SCALAR"} 9958
112              
113             This level of detail is unlikely to be useful for most generic production
114             purposes but may be helpful to set in specific processes when investigating
115             specific memory-related issues for a limited time.
116              
117             For an even greater level of detail, set the value to 2 to additionally obtain
118             another breakdown of blessed objects by class:
119              
120             # HELP perl_heap_svs_by_class Number of SVs classified by class
121             # TYPE perl_heap_svs_by_class gauge
122             ...
123             perl_heap_svs_by_class{class="Net::Prometheus"} 1
124             perl_heap_svs_by_class{class="Net::Prometheus::PerlCollector"} 1
125             perl_heap_svs_by_class{class="Net::Prometheus::ProcessCollector::linux"} 1
126              
127             Note that this will yield a large amount of output for any non-trivially sized
128             program, so should only be enabled under carefully-controlled conditions.
129              
130             The value of this variable can be overridden on a per-collection basis by
131             passing the option
132              
133             =for highlighter language=perl
134              
135             Net::Prometheus->render( { perl_collector_detail => 1 } ); # or 2
136              
137             This may be more convenient for short-term traces from exporters that parse
138             HTTP query parameters into collector options.
139              
140             =for highlighter
141              
142             GET .../metrics?perl_collector_detail=1
143              
144             =cut
145              
146             sub new
147             {
148 4     4 0 13 my $class = shift;
149              
150 4         18 return bless {}, $class;
151             }
152              
153             # Might as well keep these as constants
154             use constant
155 10     10   81 PERL_VERSION => ( $^V =~ m/^v(.*)$/ )[0];
  10         39  
  10         5056  
156              
157             sub collect
158             {
159 7     7 0 18 shift;
160 7         24 my ( $opts ) = @_;
161              
162 7 50 33     76 local $DETAIL = $opts->{perl_collector_detail} if $opts and exists $opts->{perl_collector_detail};
163              
164 7         69 my @ret = (
165             MetricSamples( "perl_info", gauge => "Information about the Perl interpreter",
166             [ Sample( "perl_info", [ version => PERL_VERSION ], 1 ) ] ),
167             );
168              
169 7         649 if( HAVE_XS ) {
170 7         21793 my ( $arenas, $svs, $svs_by_type, $svs_by_class ) = count_heap( $DETAIL );
171              
172 7         69 push @ret,
173             MetricSamples( "perl_heap_arenas", gauge => "Number of arenas in the Perl heap",
174             [ Sample( "perl_heap_arenas", [], $arenas ) ] ),
175             MetricSamples( "perl_heap_svs", gauge => "Number of SVs in the Perl heap",
176             [ Sample( "perl_heap_svs", [], $svs ) ] );
177              
178 7 100       1500 if( $svs_by_type ) {
179             push @ret, MetricSamples( "perl_heap_svs_by_type", gauge => "Number of SVs classified by type",
180 2         22 [ map { Sample( "perl_heap_svs_by_type", [ type => $_ ], $svs_by_type->{$_} ) } sort keys %$svs_by_type ] );
  20         750  
181             }
182              
183 7 100       197 if( $svs_by_class ) {
184             push @ret, MetricSamples( "perl_heap_svs_by_class", gauge => "Number of SVs classified by class",
185 1         17 [ map { Sample( "perl_heap_svs_by_class", [ class => $_ ], $svs_by_class->{$_} ) } sort keys %$svs_by_class ] );
  24         1175  
186             }
187             }
188              
189 7         389 return @ret;
190             }
191              
192             =head1 AUTHOR
193              
194             Paul Evans
195              
196             =cut
197              
198             0x55AA;