File Coverage

blib/lib/Tail/Stat/Plugin/apache.pm
Criterion Covered Total %
statement 12 64 18.7
branch 0 30 0.0
condition 0 2 0.0
subroutine 4 9 44.4
pod 5 5 100.0
total 21 110 19.0


line stmt bran cond sub pod time code
1             package Tail::Stat::Plugin::apache;
2              
3             =head1 NAME
4              
5             Tail::Stat::Plugin::apache - Statistics collector for Apache web-server
6              
7             =cut
8              
9              
10 1     1   1123 use strict;
  1         2  
  1         27  
11 1     1   4 use warnings qw(all);
  1         2  
  1         54  
12              
13              
14             =head1 SYNOPSIS
15              
16             tstatd -o clf apache httpd.access_log
17              
18              
19             =head1 LOG FORMATS
20              
21             Apache has predefined log format named B. This format defined as:
22              
23             LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
24              
25             This format produces such lines:
26              
27             1.2.3.4 - - [03/Feb/2010:00:01:03 +0300] "GET / HTTP/1.0" 200 89422 "http://www.rambler.ru/" "Opera/9.80"
28              
29             You can extend this formats with '%T' characters for logging time taken
30             to serve the request:
31              
32             LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" rt=%T" timed
33              
34             Extended format creates log records like this:
35              
36             1.2.3.4 - - [03/Feb/2010:00:01:03 +0300] "GET / HTTP/1.0" 200 89422 "http://www.rambler.ru/" "Opera/9.80" rt=2.929
37              
38              
39             =head1 OPTIONS
40              
41             =over
42              
43             =item C
44              
45             Simplify regular expression (don't accumulate information about client timing).
46              
47             =back
48              
49              
50             =head1 STATISTICS
51              
52              
53             =head2 Overall statistics
54              
55              
56             =head3 HTTP traffic
57              
58             =over
59              
60             =item C
61              
62             Total number of served requests.
63              
64             =item C
65              
66             Total number of sent bytes.
67              
68             =item C
69              
70             Total number of malformed requests.
71              
72             =back
73              
74              
75             =head3 HTTP methods
76              
77             =over
78              
79             =item C
80              
81             Total number of served HEAD requests.
82              
83             =item C
84              
85             Total number of served GET requests.
86              
87             =item C
88              
89             Total number of served subrequests.
90              
91             =item C
92              
93             Total number of served POST requests.
94              
95             =item C
96              
97             Total number of served another types of requests.
98              
99             =back
100              
101              
102             =head3 HTTP versions
103              
104             =over
105              
106             =item C
107              
108             Total number of served HTTP/0.9 requests.
109              
110             =item C
111              
112             Total number of served HTTP/1.0 requests.
113              
114             =item C
115              
116             Total number of served HTTP/1.1 requests.
117              
118             =back
119              
120              
121             =head3 HTTP statuses
122              
123             =over
124              
125             =item C
126              
127             Total number of served requests with status of xxx.
128              
129             =item C
130              
131             Total number of served requests with status of 100-199.
132              
133             =item C
134              
135             Total number of served requests with status of 200-299.
136              
137             =item C
138              
139             Total number of served requests with status of 300-399.
140              
141             =item C
142              
143             Total number of served requests with status of 400-499.
144              
145             =item C
146              
147             Total number of served requests with status of 500-599.
148              
149             =back
150              
151              
152             =head2 Last statistics
153              
154              
155             =head3 HTTP traffic
156              
157             =over
158              
159             =item C
160              
161             Total number of served requests during last window.
162              
163             =item C
164              
165             Total number of sent bytes during last window.
166              
167             =item C
168              
169             Total amount of time elapsed to serve requests during last window
170             B available unless C option in use.
171              
172             =back
173              
174             =cut
175              
176              
177 1     1   4 use base qw(Tail::Stat::Plugin);
  1         2  
  1         108  
178 1     1   6 use List::Util qw(sum);
  1         1  
  1         1085  
179              
180              
181             sub regex {
182 0     0 1   my $self = shift;
183              
184 0           my $re = qr{
185             ^
186             (\S+) # remote address [0]
187             \s
188             (\S+) # ident [1]
189             \s
190             (\S+) # remote user [2]
191             \s
192             \[([^\]]+)\] # time local [3]
193             \s
194             "(?: # request
195             ([A-Z]+) # http method [4]
196             \s+
197             ( # request uri [5]
198             /\S* # abs_path
199             |
200             http://\S* # absoluteURI
201             )
202             (?: # http version > 0.9
203             \s+
204             HTTP/(1\.[01]) # http version [6]
205             )?
206             |
207             ([^"]*) # malformed request [7]
208             )"
209             \s
210             ([1-5]\d{2}) # http status [8]
211             \s
212             (\d+|-) # content length [9]
213             \s
214             "([^"]*)" # referrer [10]
215             \s
216             "([^"]*)" # user agent [11]
217             }x;
218             $re .= qr{
219             (?:
220             rt=([\d\.]+) # request time [12]
221             |
222             .
223             )*
224 0 0         }x unless $self->{clf};
225              
226 0           return $re;
227             }
228              
229              
230             sub process_data {
231 0     0 1   my $self = shift;
232 0           my ($ref,$pub,$prv,$win) = @_;
233              
234 0           $pub->{http_request}++;
235 0           $win->{http_request}++;
236              
237 0 0         unless ($ref->[9] eq '-') {
238 0           $pub->{http_byte} += $ref->[9];
239 0           $win->{http_byte} += $ref->[9];
240             }
241              
242 0 0         if ($ref->[4]) { # method
243 0           $pub->{'http_method_'.$ref->[4]}++;
244 0 0         if ($ref->[6]) { # version
    0          
245 0           $pub->{'http_version_'.$ref->[6]}++;
246             } elsif ($ref->[4] ne 'INC') {
247 0           $pub->{'http_version_0.9'}++;
248             }
249             } else {
250 0           $pub->{malformed_request}++;
251             }
252              
253 0           $pub->{'http_status_'.$ref->[8]}++;
254              
255             # extended part
256 0 0         unless ($self->{clf}) {
257 0 0         $win->{request_time} += $ref->[12] if $ref->[12];
258             }
259              
260 0           return 1;
261             }
262              
263              
264             sub process_window {
265 0     0 1   my $self = shift;
266 0           my ($pub,$prv,$wins) = @_;
267              
268 0 0         for my $x ( qw( http_request http_byte ),
269             $self->{clf} ? () : qw( request_time )
270             ) {
271 0   0       $pub->{'last_'.$x} = sum ( map { $_->{$x} || 0 } @$wins ) || 0;
272             }
273             }
274              
275              
276             sub stats_zone {
277 0     0 1   my ($self,$zone,$pub,$prv,$wins) = @_;
278              
279             # required keys defaults
280 0           my %out = map { $_ => 0 } qw(
281              
282             malformed_request
283              
284             http_request
285             last_http_request
286              
287             http_byte
288             last_http_byte
289              
290             http_method_head
291             http_method_get
292             http_method_inc
293             http_method_post
294             http_method_other
295              
296             http_version_0_9
297             http_version_1_0
298             http_version_1_1
299              
300             http_status_1xx
301             http_status_2xx
302             http_status_3xx
303             http_status_4xx
304             http_status_5xx
305              
306 0 0         ), $self->{clf} ? () : qw(
307              
308             last_request_time
309              
310             );
311              
312              
313             # agregate required keys
314 0           for ( keys %$pub ) {
315              
316             # http_method
317 0 0         /^http_method_(HEAD|GET|INC|POST)/ and do {
318 0           $out{'http_method_'. lc $1} += $pub->{$_};
319 0           next;
320             };
321 0 0         /^http_method_/ and do {
322 0           $out{'http_method_other'} += $pub->{$_};
323 0           next;
324             };
325              
326             # http_status
327 0 0         /^http_status_([1-5])/ and do {
328 0           $out{'http_status_'. $1.'xx'} += $pub->{$_};
329             # particular statuses
330 0           $out{$_} += $pub->{$_};
331 0           next;
332             };
333              
334             # http_version
335 0 0         /^http_version_(\S+)/ and do {
336 0           (my $v = $1) =~ s/\./_/g;
337 0           $out{'http_version_'. $v} += $pub->{$_};
338 0           next;
339             };
340              
341             # extended mode
342 0 0         unless ($self->{clf}) {
343             # copy remainings values as is
344 0           $out{$_} += $pub->{$_};
345              
346 0           next;
347             }
348              
349             # simple attributes
350             /^(?:
351             malformed_request |
352             http_request |
353             last_http_request |
354             http_byte |
355             last_http_byte
356 0 0         )$/x and do {
357 0           $out{$_} += $pub->{$_};
358 0           next;
359             };
360             }
361              
362 0           map { $_.': '.$out{$_} } sort keys %out;
  0            
363             }
364              
365              
366             sub parse_error {
367 0     0 1   'notice'
368             }
369              
370              
371             =head1 AUTHOR
372              
373             Oleg A. Mamontov, C<< >>
374              
375              
376             =head1 COPYRIGHT
377              
378             This program is free software; you can redistribute it and/or modify it
379             under the terms of either: the GNU General Public License as published
380             by the Free Software Foundation; or the Artistic License.
381              
382             See http://dev.perl.org/licenses/ for more information.
383              
384             =cut
385              
386             1;
387