File Coverage

blib/lib/Graphite/Enumerator.pm
Criterion Covered Total %
statement 24 51 47.0
branch 6 20 30.0
condition 0 5 0.0
subroutine 6 10 60.0
pod 6 6 100.0
total 42 92 45.6


line stmt bran cond sub pod time code
1             package Graphite::Enumerator;
2              
3 1     1   561 use 5.14.1;
  1         3  
  1         33  
4 1     1   4 use Carp qw/croak/;
  1         1  
  1         50  
5 1     1   845 use LWP::UserAgent;
  1         177591  
  1         26  
6 1     1   9 use JSON;
  1         1  
  1         9  
7              
8             our $VERSION = '0.01';
9              
10             # Recognized constructor options:
11             # - host (base URL)
12             # - basepath (top-level metric to scan)
13             # - lwp_options (hashref)
14              
15             sub new {
16 1     1 1 355 my ($class, %args) = @_;
17 1 50       6 $args{host} or croak "No host provided";
18 1 50       4 $args{host} =~ m{^https?://} or $args{host} = "http://".$args{host};
19 1 50       4 $args{host} =~ m{/$} or $args{host} .= '/';
20 1 50       3 if (defined $args{basepath}) {
21 1 50       4 $args{basepath} =~ /\.$/ or $args{basepath} .= '.';
22             }
23             else {
24 0         0 $args{basepath} = '';
25             }
26 1         5 $args{_finder} = $args{host} . 'metrics/find?format=completer&query=';
27 1 50       2 $args{_ua} = LWP::UserAgent->new( %{ $args{lwp_options} || {} } );
  1         10  
28 1         2626 bless \%args, $class;
29             }
30              
31             sub enumerate {
32 0     0 1 0 my ($self, $callback, $path, $level) = @_;
33 0   0     0 $path //= $self->{basepath};
34 0   0     0 $level //= 0;
35 0         0 my $url = $self->{_finder} . $path;
36 0         0 my $res = $self->{_ua}->get($url);
37 0 0       0 if ($res->is_success) {
38 0         0 my $completer_answer = eval { decode_json($res->content) };
  0         0  
39 0 0       0 if (!$completer_answer) {
40 0         0 $self->log_warning("URL <$url>: Couldn't decode JSON string: <" . $res->content . ">: $@");
41 0         0 return 0;
42             }
43 0 0       0 return 0 if !$completer_answer->{metrics};
44 0         0 for my $metric (@{ $completer_answer->{metrics} }) {
  0         0  
45 0 0       0 if ($metric->{is_leaf}) {
46 0         0 $callback->($metric->{path}, $level);
47             }
48             else {
49 0         0 $self->enumerate($callback, $metric->{path}, $level + 1);
50             }
51             }
52 0         0 return 1;
53             }
54             else {
55 0         0 $self->log_warning("Can't get <$url>: " . $res->status_line);
56 0         0 return 0;
57             }
58             }
59              
60             sub host {
61 1     1 1 5 my ($self) = @_;
62 1         9 return $self->{host};
63             }
64              
65             sub ua {
66 0     0 1   my ($self) = @_;
67 0           return $self->{_ua};
68             }
69              
70             sub log_message {
71 0     0 1   my ($self, $message) = @_;
72 0           print $message, "\n";
73             }
74              
75             sub log_warning {
76 0     0 1   my ($self, $message) = @_;
77 0           warn $message, "\n";
78             }
79              
80             1;
81              
82             =head1 NAME
83              
84             Graphite::Enumerator - Utility module to recursively enumerate graphite metrics
85              
86             =head1 SYNOPSIS
87              
88             my $gren = Graphite::Enumerator->new(
89             host => 'https://graphite.example.com',
90             basepath => 'general.metrics',
91             lwp_options => {
92             env_proxy => 1,
93             keep_alive => 1,
94             },
95             );
96             $gren->enumerate(sub {
97             my ($path) = @_;
98             print "Found metric $path !\n";
99             });
100              
101             =head1 METHODS
102              
103             =head2 Graphite::Enumerator->new(%args)
104              
105             The constructor recognizes 3 arguments:
106              
107             host => host name (in that case, the protocol defaults to http) or base URL
108             basepath => top-level metric namespace to scan
109             lwp_options => hash of options to initialize LWP::UserAgent internally
110              
111             =head2 $g->enumerate($coderef)
112              
113             Calls C<$coderef> for each metric under the basepath, with two parameters:
114             1. the metric name as a string; 2. the depth level of the metric relative
115             to the base path (starting at 0).
116              
117             =head2 $g->host
118              
119             Returns the host passed to the constructor (with eventually
120             C prepended).
121              
122             =head2 $g->ua
123              
124             Returns the internal LWP::UserAgent object.
125              
126             =head2 $g->log_message($message)
127              
128             Prints the C<$message> to STDOUT.
129              
130             =head2 $g->log_warning($message)
131              
132             Warns about the C<$message>.
133              
134             =head1 ACKNOWLEDGMENT
135              
136             This module was originally developed for Booking.com.
137             With approval from Booking.com, this module was generalized
138             and put on CPAN, for which the author would like to express
139             his gratitude.
140              
141             =head1 AUTHOR
142              
143             Rafael Garcia-Suarez, Ergs@consttype.orgE
144              
145             This code is available under the same license as Perl version 5.10.1 or higher.
146              
147             A git repository for this module is available at L.
148              
149             =cut