File Coverage

blib/lib/Monitor/MetricsAPI.pm
Criterion Covered Total %
statement 27 34 79.4
branch 6 12 50.0
condition 2 3 66.6
subroutine 7 9 77.7
pod 3 3 100.0
total 45 61 73.7


line stmt bran cond sub pod time code
1 13     13   1276782 use strict;
  13         29  
  13         478  
2 13     13   66 use warnings;
  13         22  
  13         784  
3              
4             package Monitor::MetricsAPI;
5             # ABSTRACT: Metrics collection and reporting for Perl applications.
6             $Monitor::MetricsAPI::VERSION = '0.900';
7 13     13   6961 use namespace::autoclean;
  13         216588  
  13         63  
8 13     13   9233 use Moose;
  13         5570289  
  13         109  
9 13     13   93536 use MooseX::ClassAttribute;
  13         1021234  
  13         63  
10              
11 13     13   3940564 use Monitor::MetricsAPI::Collector;
  13         58  
  13         5544  
12              
13             =head1 NAME
14              
15             Monitor::MetricsAPI - Metrics collection and reporting for Perl applications.
16              
17             =head1 SYNOPSIS
18              
19             use Monitor::MetricsAPI;
20              
21             my $collector = Monitor::MetricsAPI->create(
22             listen => '*:8000',
23             metrics => {
24             messages => {
25             incoming => 'counter',
26             outgoing => 'counter',
27             },
28             networks => {
29             configured => 'gauge',
30             connected => 'gauge',
31             },
32             users => {
33             total => sub { $myapp->total_user_count() },
34             }
35             }
36             );
37              
38             # Using the collector object methods:
39             $collector->metric('messages/incoming')->add(1);
40             $collector->metric('networks/connected')->set(3);
41              
42             # Using a global collector via class methods:
43             Monitor::MetricsAPI->metric('messages/incoming')->increment;
44              
45             =head1 DESCRIPTION
46              
47             Monitor::MetricsAPI provides functionality for the collection of arbitrary
48             application metrics within any event-driven Perl application, as well as the
49             reporting of those statistics via a JSON-over-HTTP API for consumption by
50             external systems monitoring tools.
51              
52             Using Monitor::MetricsAPI first requires that you create the metrics collector
53             (and accompanying reporting server), by calling create() and providing it with
54             an address and port to which it should listen. Additionally, any metrics you
55             wish the collector to track should be defined.
56              
57             The example above has created a new collector which will listen to all network
58             interfaces on port 8000. It has also defined two metrics of type 'counter' and
59             one metric which will invoke the provided subroutine every time the reporting
60             server displays the value. Refer to L<Monitor::MetricsAPI::Metric> for more
61             details on support metric types and their usage.
62              
63             As your app runs, it can manipulate metrics by calling various methods via the
64             collector object:
65              
66             For applications where passing around the collector object to all of your
67             functions and libraries is not possible, you may also allow Monitor::MetricsAPI
68             to maintain the collector as a global for you. This is done automatically for
69             the first collector object you create (and very few applications will want to
70             use more than one collector anyway).
71              
72             Instead of invoking metric methods on a collector object, invoke them as class
73             methods:
74              
75             =cut
76              
77             class_has 'collector' => (
78             is => 'ro',
79             isa => 'Monitor::MetricsAPI::Collector',
80             predicate => '_has_global',
81             writer => '_set_global',
82             );
83              
84             =head1 METHODS
85              
86             =head2 create ( listen => '...', metrics => { ... } )
87              
88             Creates a new collector, which in turn initializes the defined metrics and
89             binds to the provided network interfaces and ports. If there is already a
90             global collector, then any metric definitions passed into this class method
91             will be added to the existing collector before it is returned.
92              
93             =cut
94              
95             sub create {
96 14     14 1 1613 my ($class, @args) = @_;
97              
98 14 100       900 if ($class->_has_global) {
99 2 100 66     18 if (@args && @args % 2 == 0) {
100 1         4 my %args = @args;
101              
102 1 50       4 if (exists $args{'metrics'}) {
103 1         30 $class->collector->add_metrics($args{'metrics'});
104             }
105              
106 1 50       5 if (exists $args{'listen'}) {
107 0         0 $class->collector->add_server($args{'listen'});
108             }
109             }
110             } else {
111 12         693 $class->_set_global(
112             Monitor::MetricsAPI::Collector->new(
113             @args
114             )
115             );
116             }
117              
118 14         555 return $class->collector;
119             }
120              
121             =head2 metric ($name)
122              
123             Returns the L<Monitor::MetricsAPI::Metric> object for the given name. Metric
124             names are collapsed to a slash-delimited string, which mirrors the path used
125             by the reporting HTTP server to display individual metrics. Thus, this:
126              
127             Monitor::MetricsAPI->create(
128             metrics => {
129             server => {
130             version => {
131             major => 'string',
132             minor => 'string',
133             }
134             }
135             }
136             );
137              
138             Creates two metrics:
139              
140             =over
141              
142             =item 1. server/version/major
143              
144             =item 2. server/version/minor
145              
146             =back
147              
148             The metric object returned by this method may then be modified, according to
149             its own methods documented in L<Monitor::MetricsAPI::Metric> and the
150             type-specific documentation, or its value may be accessed via the standard
151             value() metric method.
152              
153             Updating a metric:
154              
155             $collector->metric('users/total')->set($user_count);
156              
157             Retrieving the current value of a metric:
158              
159             $collector->metric('users/total')->value;
160              
161             =cut
162              
163             sub metric {
164 0     0 1   my $class = shift;
165              
166 0 0         die "no collector has been created yet" unless $class->_has_global;
167 0           return $class->collector->metric(@_);
168             }
169              
170             =head2 add_metric ($name, $type, $callback)
171              
172             Allows for adding a new metric to the collector as your application is running,
173             instead of having to define everything at startup.
174              
175             If the metric already exists, this method will be a noop as long as all of the
176             metric options match (i.e. the existing metric is of the same type as what you
177             specified in add_metric()). If the metric already exists and you have specified
178             options which do not match the existing ones, a warning will be emitted and no
179             other actions will be taken.
180              
181             Both $name and $type are required. If $type is 'callback' then a subroutine
182             reference must be passed in for $callback. Refer to the documentation in
183             L<Monitor::MetricsAPI::Metric> for details on individual metric types.
184              
185             =cut
186              
187             sub add_metric {
188 0     0 1   my $class = shift;
189              
190 0 0         die "no collector has been created yet" unless $class->_has_global;
191 0           return $class->collector->add_metric(@_);
192             }
193              
194             =head1 DEPENDENCIES
195              
196             Monitor::MetricsAPI primarily makes use of the CPAN distributions listed below,
197             though others may also be required for building, testing, and/or operation. For
198             the complete list of dependencies, please refer to the distribution metadata.
199              
200             =over
201              
202             =item * L<AnyEvent>
203              
204             =item * L<Twiggy>
205              
206             =item * L<Dancer2>
207              
208             =item * L<Moose>
209              
210             =back
211              
212             =head1 BUGS
213              
214             There are no known bugs at the time of this release.
215              
216             Please report any bugs or problems to the module's Github Issues page:
217              
218             L<https://github.com/jsime/monitor-metricsapi/issues>
219              
220             Pull requests are welcome.
221              
222             =head1 AUTHORS
223              
224             Jon Sime <jonsime@gmail.com>
225              
226             =head1 LICENSE AND COPYRIGHT
227              
228             This software is copyright (c) 2015 by OmniTI Computer Consulting, Inc.
229              
230             This module is free software; you can redistribute it and/or
231             modify it under the same terms as Perl itself. See L<perlartistic>.
232              
233             This program is distributed in the hope that it will be useful,
234             but WITHOUT ANY WARRANTY; without even the implied warranty of
235             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
236              
237             =cut
238              
239             __PACKAGE__->meta->make_immutable;
240             1;