File Coverage

blib/lib/Monitor/MetricsAPI/Metric/List.pm
Criterion Covered Total %
statement 29 30 96.6
branch 6 8 75.0
condition 5 9 55.5
subroutine 7 7 100.0
pod 2 2 100.0
total 49 56 87.5


line stmt bran cond sub pod time code
1 13     13   76 use strict;
  13         26  
  13         505  
2 13     13   94 use warnings;
  13         21  
  13         793  
3              
4             package Monitor::MetricsAPI::Metric::List;
5             $Monitor::MetricsAPI::Metric::List::VERSION = '0.900';
6 13     13   79 use namespace::autoclean;
  13         61  
  13         108  
7 13     13   896 use Moose;
  13         22  
  13         147  
8              
9             extends 'Monitor::MetricsAPI::Metric';
10              
11             =head1 NAME
12              
13             Monitor::MetricsAPI::Metric::List - List metric class for Monitor::MetricsAPI
14              
15             =head1 SYNOPSIS
16              
17             use Monitor::MetricsAPI;
18              
19             my $collector = Monitor::MetricsAPI->new(
20             metrics => { messages => { processing_times => 'list' } }
21             );
22              
23             $collector->metric('messages/processing_times')->limit(1_000);
24              
25             # Later on while processing an incoming message...
26             use Time::HiRes qw( gettimeofday, tv_interval );
27              
28             my $t_start = [gettimeofday];
29             # ... do a bunch of work ...
30             my $t_end = [gettimeofday];
31              
32             $collector->metric('messages/processing_times')->push(
33             tv_interval($t_start, $t_end)
34             );
35              
36             =head1 DESCRIPTION
37              
38             List metrics allow you to track multiple related values inside of a single
39             metric, and to set limits on the number of values which will be stored at any
40             given time. As more values are added, the oldest ones are evacuated to keep the
41             list contents (and conequently, memory usage) fixed.
42              
43             It may not be terribly useful to have your monitoring system looking at list
44             metrics directly, but they provide a very useful base for constructing derived
45             metrics by defining companion callback metrics that perform a computation on
46             the list metric's values.
47              
48             For instance, in the example above we track the most recent 1,000 response
49             times for messages our application processes. A companion callback metric might
50             be defined to compute the average of those values, thus giving us a single
51             metric that can be retrieved easily showing a rolling average of our
52             application's performance on a particular task.
53              
54             use List::Util qw( sum0 );
55              
56             $collector->add_metric('messages/processing_times_average', 'callback',
57             sub {
58             sum0(@{$collector->metric('messages/processing_times')->value})
59             /
60             scalar(@{$collector->metric('messages/processing_times')->value})
61             }
62             );
63              
64             =head1 METHODS
65              
66             String metrics do not provide any additional methods beyond the base methods
67             offered by L<Monitor::MetricsAPI::Metric>.
68              
69             =cut
70              
71             has '+_value' => (
72             isa => 'ArrayRef',
73             default => sub { [] },
74             );
75              
76             =head2 limit
77              
78             Sets or returns the current limit on the number of items in the list metric. A
79             negative or undefined value indicates that there is no limit to the number of
80             elements. This is generally inadvisable due to memory consumption.
81              
82             When a limit is set, items at the tail of the list will be dropped to make room
83             for new entries as necessary.
84              
85             =cut
86              
87             has 'limit' => (
88             is => 'rw',
89             isa => 'Int',
90             predicate => 'has_limit',
91             clearer => 'clear_limit',
92             trigger => \&_limit_change,
93             );
94              
95             =head2 has_limit
96              
97             Returns a true value if the metric has a limit set, otherwise false.
98              
99             =head2 clear_limit
100              
101             Removes list element limit from the metric if one has been set.
102              
103             =cut
104              
105             sub _limit_change {
106 2     2   3 my ($self, $limit, $old_limit) = @_;
107              
108 2 50 33     9 if (defined $limit && $limit < 0) {
109 0         0 return $self->clear_limit;
110             }
111              
112 2 100 66     10 if (defined $limit && $limit < $self->size) {
113 1         4 my $drop = $self->size - $limit;
114 1         5 $self->_set_value([@{$self->_value}[$drop..($self->size -1)]]);
  1         31  
115             }
116             }
117              
118             =head2 push ( @values )
119              
120             Adds a new entry to the list metric. If a limit is set on the metric, this
121             method will have the side effect of dropping the oldest entry, or entries if
122             you push multiple values, to make room for the new ones.
123              
124             $collector->metric('messages/processing_times')->push($duration);
125              
126             =cut
127              
128             sub push {
129 3     3 1 6 my ($self, @values) = @_;
130              
131 3 50       9 return unless @values;
132              
133 3 100 66     110 if ($self->has_limit && $self->size + scalar(@values) > $self->limit) {
134 1         3 my $drop = ($self->size + scalar(@values)) - $self->limit;
135              
136 1         4 $self->_set_value([@{$self->_value}[$drop..($self->size -1)], @values]);
  1         31  
137             } else {
138 2         2 push(@{$self->_value}, @values);
  2         72  
139             }
140             }
141              
142             =head2 size
143              
144             Returns the number of elements currently stored in the list metric.
145              
146             =cut
147              
148             sub size {
149 9     9 1 12 my ($self) = @_;
150              
151 9         9 return scalar @{$self->_value};
  9         307  
152             }
153              
154             =head1 AUTHORS
155              
156             Jon Sime <jonsime@gmail.com>
157              
158             =head1 LICENSE AND COPYRIGHT
159              
160             This software is copyright (c) 2015 by OmniTI Computer Consulting, Inc.
161              
162             This module is free software; you can redistribute it and/or
163             modify it under the same terms as Perl itself. See L<perlartistic>.
164              
165             This program is distributed in the hope that it will be useful,
166             but WITHOUT ANY WARRANTY; without even the implied warranty of
167             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
168              
169             =cut
170              
171             __PACKAGE__->meta->make_immutable;
172             1;