File Coverage

blib/lib/Metrics/Any/Adapter.pm
Criterion Covered Total %
statement 33 33 100.0
branch 7 8 87.5
condition 2 3 66.6
subroutine 8 8 100.0
pod 0 4 0.0
total 50 56 89.2


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, 2020 -- leonerd@leonerd.org.uk
5              
6             package Metrics::Any::Adapter 0.10;
7              
8 13     13   967628 use v5.14;
  13         77  
9 13     13   76 use warnings;
  13         41  
  13         339  
10              
11 13     13   79 use Carp;
  13         38  
  13         7382  
12              
13             =head1 NAME
14              
15             C - set the C adapter for the program
16              
17             =head1 SYNOPSIS
18              
19             In a program or top-level program-like module:
20              
21             use Metrics::Any::Adapter 'Prometheus';
22              
23             =head1 DESCRIPTION
24              
25             The C statement which loads this module sets the adapter module for
26             L to report metrics generated by an modules the program uses.
27              
28             The first value passed should be a string giving the name of an adapter
29             module, which will be expected under the C-prefix.
30             This module will be loaded and set as the adapter to use. Any additional
31             arguments will be passed to the constructor of the adapter instance.
32              
33             use Metrics::Any::Adapter Custom => "another arg";
34              
35             # implies
36             $adapter = Metrics::Any::Adapter::Custom->new( "another arg" );
37              
38             =head1 ENVIRONMENT
39              
40             =head2 METRICS_ANY_ADAPTER
41              
42             I
43              
44             Sets the default adapter type to use if the program has not otherwise
45             requested one.
46              
47             Normally this is set to C, which loads L.
48             By overriding this to a different value, a default adapter can be loaded
49             without modifying the program. This may be useful for example, when running
50             unit tests:
51              
52             $ METRICS_ANY_ADAPTER=Stderr ./Build test
53              
54             Additional arguments can be specified after a colon, separated by commas or
55             equals signs.
56              
57             $ METRICS_ANY_ADAPTER=File:path=metrics.log ./program.pl
58              
59             Note that if a program requests a specific adapter that will override this
60             variable.
61              
62             A limited attempt is made at supporting nested arguments wrapped in square
63             brackets, to allow basic operation of the L
64             adapter via this variable to itself pass arguments into child adapters:
65              
66             $ METRICS_ANY_ADAPTER=Tee:Prometheus,[File:path=metrics.log] perl ...
67              
68             This should be considered a best-effort scenario useful for short-term testing
69             and debugging. For more complex requirements in your script or program, it is
70             better to use the import arguments directly as then any perl data structures
71             can be passed around.
72              
73             =cut
74              
75             sub import
76             {
77 23     23   1109 my $pkg = shift;
78 23         51 my $caller = caller;
79 23         74 $pkg->import_into( $caller, @_ );
80             }
81              
82             # Class method so Metrics::Any::Adapter::Tee can share it
83             sub split_type_string
84             {
85 4     4 0 1197 shift;
86 4         12 my ( $str ) = @_;
87              
88 4         23 my ( $type, $argstr ) = split m/[:,]/, $str, 2;
89 4         8 my @args;
90              
91 4         13 while( length $argstr ) {
92 7 100       20 if( $argstr =~ m/^\[/ ) {
93             # Extract the entire contents of the [...] bracket
94             # TODO: Support deeper nesting somehow? Currently this is only used
95             # for using the Tee adapter via the $METRICS_ANY_ADAPTER variable
96 1 50       8 $argstr =~ s/^\[(.*?)\](?:,|=|$)// or
97             croak "Missing close bracket ] in adapter type string";
98 1         6 push @args, $1;
99             }
100             else {
101             # All up to the next , = or endofstring
102 6         25 $argstr =~ s/^(.*?)(?:,|=|$)//;
103 6         20 push @args, $1;
104             }
105             }
106              
107 4         32 return ( $type, @args );
108             }
109              
110             sub class_for_type
111             {
112 13     13 0 24 shift;
113 13         53 my ( $type ) = @_;
114              
115 13         42 my $class = "Metrics::Any::Adapter::$type";
116 13 100       156 unless( $class->can( 'new' ) ) {
117 7         57 ( my $file = "$class.pm" ) =~ s{::}{/}g;
118 7         3836 require $file;
119             }
120 13         87 return $class;
121             }
122              
123             my $adaptertype = "Null";
124             my @adapterargs;
125             if( my $val = $ENV{METRICS_ANY_ADAPTER} ) {
126             ( $adaptertype, @adapterargs ) = __PACKAGE__->split_type_string( $val );
127             }
128              
129             sub import_into
130             {
131 23     23 0 70 my ( $pkg, $caller, @args ) = @_;
132              
133 23 100       13452 ( $adaptertype, @adapterargs ) = @args if @args;
134             }
135              
136             my $adapter;
137              
138             sub adapter
139             {
140 14     14 0 12608 shift;
141              
142 14   66     133 return $adapter //= __PACKAGE__->class_for_type( $adaptertype )->new( @adapterargs );
143             }
144              
145             =head1 AUTHOR
146              
147             Paul Evans
148              
149             =cut
150              
151             0x55AA;