File Coverage

blib/lib/Catalyst/Plugin/Statsd.pm
Criterion Covered Total %
statement 21 21 100.0
branch 1 2 50.0
condition n/a
subroutine 7 7 100.0
pod 2 2 100.0
total 31 32 96.8


line stmt bran cond sub pod time code
1             package Catalyst::Plugin::Statsd;
2              
3             # ABSTRACT: Log Catalyst stats to statsd
4              
5 2     2   4502444 use v5.14;
  2         23  
6              
7 2     2   14 use Moose::Role;
  2         5  
  2         25  
8              
9 2     2   12494 use POSIX qw/ ceil /;
  2         5  
  2         24  
10 2     2   3729 use Ref::Util qw/ is_plain_arrayref /;
  2         6  
  2         204  
11              
12             # RECOMMEND PREREQ: Ref::Util::XS
13              
14 2     2   26 use namespace::autoclean;
  2         4  
  2         24  
15              
16             requires qw/ log_stats /;
17              
18             our $VERSION = 'v0.8.2';
19              
20              
21             sub statsd_client {
22 4     4 1 13 my ($c) = @_;
23 4         15 return $c->req->env->{'psgix.monitor.statsd'};
24             }
25              
26              
27              
28             sub statsd_metric_name_filter {
29 6     6 1 16 my ($c, $stat) = @_;
30              
31 6 50       20 return "$stat" unless is_plain_arrayref($stat);
32              
33 6         19 my $metric = "catalyst.stats." . $stat->[1] . ".time";
34 6         37 $metric =~ s/[^\w\-_]+/./g;
35              
36 6         30 return $metric;
37             }
38              
39             around log_stats => sub {
40             my ( $next, $c ) = @_;
41              
42             state $config = $c->config->{'Plugin::Statsd'} // {};
43              
44             if ( my $client = $c->statsd_client) {
45              
46             my $stat = [ -1, "catalyst.response.time", $c->stats->elapsed ];
47             my $metric = $c->statsd_metric_name_filter($stat) or next;
48              
49             $client->timing_ms( "catalyst.response.time",
50             ceil( $stat->[2] * 1000 ) );
51              
52             foreach my $stat ( $c->stats->report ) {
53              
54             my $metric = $c->statsd_metric_name_filter($stat) or next;
55             my $timing = ceil( $stat->[2] * 1000 );
56              
57             $client->timing_ms( $metric, $timing );
58              
59             }
60              
61             }
62              
63             my $disabled = $config->{disable_stats_report} // !$c->debug;
64              
65             $c->$next unless $disabled;
66             };
67              
68             around finalize => sub {
69             my ($next, $c) = @_;
70              
71             if (my $client = $c->statsd_client) {
72              
73             if ($c->can("sessionid") && (my $id = $c->sessionid)) {
74             $client->set_add("catalyst.sessionid", "$id");
75             }
76             # Plack::Middleware::Session
77             elsif (my $options = $c->req->env->{'psgix.session.options'}) {
78             if (my $id = $options->{id}) {
79             $client->set_add("catalyst.sessionid", "$id");
80             }
81             }
82             }
83              
84             $c->$next();
85             };
86              
87              
88             1;
89              
90             __END__
91              
92             =pod
93              
94             =encoding UTF-8
95              
96             =head1 NAME
97              
98             Catalyst::Plugin::Statsd - Log Catalyst stats to statsd
99              
100             =head1 VERSION
101              
102             version v0.8.2
103              
104             =head1 SYNOPSIS
105              
106             use Catalyst qw/
107             Statsd
108             -Stats=1
109             /;
110              
111             use Net::Statsd::Tiny;
112              
113             __PACKAGE__->config(
114             'psgi_middleware', [
115             Statsd => {
116             client => Net::Statsd::Tiny->new,
117             },
118             ],
119             );
120              
121             # (or you can specify the Statsd middleware in your
122             # application's PSGI file.)
123              
124             =head1 DESCRIPTION
125              
126             This plugin will log L<Catalyst> timing statistics to statsd.
127              
128             =head2 CONFIGURATION
129              
130             __PACKAGE__->config(
131              
132             'Plugin::Statsd' => {
133             disable_stats_report => 0,
134             },
135              
136             );
137              
138             =head2 C<disable_stats_report>
139              
140             Enabling stats will also log a table of statistics to the Catalyst
141             log. If you do not want this, then set C<disable_stats_report>
142             to true.
143              
144             Note that if you are modifying the C<log_stats> method or using
145             another plugin that does this, then this may interfere with that if
146             you disable the stats report.
147              
148             This defaults to
149              
150             !$c->debug
151              
152             =head1 METHODS
153              
154             =head2 C<statsd_client>
155              
156             $c->statsd_client;
157              
158             Returns the statsd client.
159              
160             This is the statsd client used by L<Plack::Middleware::Statsd>.
161              
162             =head2 C<statsd_metric_name_filter>
163              
164             $c->statsd_metric_name_filter( $stat_or_name );
165              
166             This method returns the name to be used for logging stats, or C<undef>
167             if the metric should be ignored.
168              
169             Only alphanumeric characters, hyphens or underscores in namespaces are
170             accepted. All other characters are converted to dots, with consecutive
171             dots compressed into a single dot.
172              
173             If it is passed a non-arrayref, then it will stringify the argument
174             and return that.
175              
176             If it is passed an array reference, then it assumes the argument comes
177             from L<Catalyst::Stats> report and is converted into a suitable metric
178             name.
179              
180             You can override or modify this method to filter out which metrics you
181             want logged, or to change the names of the metrics.
182              
183             =head1 METRICS
184              
185             =head2 C<catalyst.response.time>
186              
187             This logs the Catalyst reponse time that is normally reported by
188             Catalyst. However, it is probably unnecessary since
189             L<Plack::Middleware::Statsd> also logs response times.
190              
191             =head2 C<catalyst.sessionid>
192              
193             If L<Catalyst::Plugin::Session> or L<Plack::Middleware::Session> is
194             used, or anything that adds a C<sessionid> method to the context, then
195             the session id is added as a set, to count the number of unique
196             sessions.
197              
198             =head2 C<catalyst.stats.*.time>
199              
200             These are metrics generated from L<Catalyst::Stats>.
201              
202             All non-word characters in the paths in an action are changed to dots,
203             e.g. the timing for an action C</foo/bar> will be logged with the
204             metric C<catalyst.stats.foo.bar.time>.
205              
206             The metric name is generated by L</statsd_metric_name_filter>.
207              
208             =head1 KNOWN ISSUES
209              
210             =head2 Custom Profiling Points
211              
212             If you have custom profiling points, then these will be treated as
213             top-level names in the C<catalyst.stats.*> namespaces, e.g.
214              
215             my $stats = $c->stats;
216             $stats->profile( begin => 'here' );
217              
218             ...
219              
220             $stats->profile( end => 'here' );
221              
222             will be logged to statsd in the C<catalyst.stats.here.time> namespace.
223              
224             If you do not want this, then you can work around this by prefixing
225             the block name with a controller name, e.g.
226              
227             $stats->profile( begin => 'controller.here' );
228              
229             =head2 Large Databases When Profiling
230              
231             When profiling your application, the size of your stats database may
232             grow quite large.
233              
234             Your database storage and retention settings should be adjusted
235             accordingly.
236              
237             =head1 SUPPORT FOR OLDER PERL VERSIONS
238              
239             Since v0.8.0, the this module requires Perl v5.14 or later.
240              
241             Future releases may only support Perl versions released in the last ten years.
242              
243             If you need this module on Perl v5.10, please use one of the v0.7.x
244             versions of this module. Significant bug or security fixes may be
245             backported to those versions.
246              
247             =head1 SEE ALSO
248              
249             =over
250              
251             =item *
252              
253             L<Catalyst::Stats>
254              
255             =item *
256              
257             L<Plack::Middleware::Statsd>
258              
259             =item *
260              
261             L<Net::Statsd::Tiny>
262              
263             =back
264              
265             =head1 SOURCE
266              
267             The development version is on github at L<https://github.com/robrwo/CatalystX-Statsd>
268             and may be cloned from L<git://github.com/robrwo/CatalystX-Statsd.git>
269              
270             =head1 BUGS
271              
272             Please report any bugs or feature requests on the bugtracker website
273             L<https://github.com/robrwo/CatalystX-Statsd/issues>
274              
275             When submitting a bug or request, please include a test-file or a
276             patch to an existing test-file that illustrates the bug or desired
277             feature.
278              
279             =head1 AUTHOR
280              
281             Robert Rothenberg <rrwo@cpan.org>
282              
283             The initial development of this module was sponsored by Science Photo
284             Library L<https://www.sciencephoto.com>.
285              
286             =head1 CONTRIBUTOR
287              
288             =for stopwords Slaven Rezić
289              
290             Slaven Rezić <slaven@rezic.de>
291              
292             =head1 COPYRIGHT AND LICENSE
293              
294             This software is Copyright (c) 2018-2023 by Robert Rothenberg.
295              
296             This is free software, licensed under:
297              
298             The Artistic License 2.0 (GPL Compatible)
299              
300             =cut