File Coverage

blib/lib/Log/Saftpresse/Plugin/Apache.pm
Criterion Covered Total %
statement 9 64 14.0
branch 0 34 0.0
condition 0 12 0.0
subroutine 3 8 37.5
pod 1 3 33.3
total 13 121 10.7


line stmt bran cond sub pod time code
1             package Log::Saftpresse::Plugin::Apache;
2              
3 1     1   1570 use Moose;
  1         2  
  1         5  
4              
5             # ABSTRACT: plugin to parse apache logs
6             our $VERSION = '1.5'; # VERSION
7              
8             extends 'Log::Saftpresse::Plugin';
9              
10             with 'Log::Saftpresse::Plugin::Role::CounterUtils';
11              
12             has 'format' => ( is => 'rw', isa => 'Str', default => 'vhost_combined');
13              
14             has 'detect_browser' => ( is => 'rw', isa => 'Bool', default => 1);
15             has 'detect_search' => ( is => 'rw', isa => 'Bool', default => 1);
16              
17 1     1   4159 use Log::Saftpresse::Log4perl;
  1         2  
  1         94  
18 1     1   560 use URI;
  1         3000  
  1         573  
19              
20             sub process {
21 0     0 1   my ( $self, $event ) = @_;
22 0           my $program = $event->{'program'};
23 0 0 0       if( ! defined $program || $program ne 'apache' ) {
24 0           return;
25             }
26              
27 0 0         if( $self->format eq 'vhost_combined' ) {
    0          
28 0           $self->parse_vhost_combined( $event );
29             } elsif( $self->format eq 'combined' ) {
30 0           $self->parse_combined( $event );
31             } else {
32 0           return;
33             }
34              
35 0 0 0       if( $self->detect_browser
      0        
36             && $self->_browser_detect_installed
37             && defined $event->{'agent'} ) {
38 0           $self->_detect_browser( $event );
39             }
40 0 0 0       if( $self->detect_search
41             && defined $event->{'referer'} ) {
42 0           $self->_detect_search( $event );
43             }
44              
45 0           $self->incr_host_one($event, 'total' );
46 0           $self->count_fields_occur( $event, 'vhost', 'code' );
47 0           $self->count_fields_value( $event, 'size' );
48              
49 0           return;
50             }
51              
52             has '_browser_detect_installed' => ( is => 'ro', isa => 'Bool', lazy => 1,
53             default => sub {
54             eval { require HTTP::BrowserDetect };
55             if( $@ ) {
56             $log->warn('HTTP::BrowserDetect is not installed. disabled detect_browser in Apache plugin! ('.$@.')');
57             return 0;
58             }
59             return 1;
60             },
61             );
62              
63             sub _detect_search {
64 0     0     my ( $self, $event ) = @_;
65 0           my %search;
66 0           my $u = URI->new( $event->{'referer'} );
67 0           my %q = $u->query_form;
68              
69 0 0         if( defined $q{'q'} ) {
70 0           $search{'keywords'} = [ split(/\s+/, $q{'q'}) ];
71 0           $search{'engine'} = $u->host;
72             }
73              
74 0 0         if( scalar %search ) {
75 0           $event->{'search'} = \%search;
76             }
77              
78 0           return;
79             }
80              
81             sub _detect_browser {
82 0     0     my ( $self, $event ) = @_;
83 0           my $b = HTTP::BrowserDetect->new( $event->{'agent'} );
84              
85 0 0         $event->{'browser'} = {
    0          
    0          
    0          
    0          
86             $b->browser ? ( 'browser' => $b->browser ) : (),
87             $b->browser_version ? ('version' => $b->browser_version) : (),
88             $b->os ? ( 'os' => $b->os ) : (),
89             $b->robot ? ('robot' => $b->robot) : (),
90             $b->mobile ? ( 'mobile' => $b->mobile ) : (),
91             };
92              
93 0           return;
94             }
95              
96             sub parse_vhost_combined {
97 0     0 0   my ( $self, $event, $msg ) = @_;
98 0 0         if( ! defined $msg ) {
99 0           $msg = $event->{'message'};
100             }
101 0           my ( $vhost, $port, $combined ) =
102             $msg =~ /^([^:]+):(\d+) (.*)$/;
103 0 0         if( ! defined $vhost ) {
104 0           return;
105             }
106 0           $event->{'vhost'} = $vhost;
107 0           $event->{'port'} = $port;
108              
109 0           $self->parse_combined( $event, $combined );
110              
111 0           return;
112             }
113              
114             sub parse_combined {
115 0     0 0   my ( $self, $event, $msg ) = @_;
116 0 0         if( ! defined $msg ) {
117 0           $msg = $event->{'message'};
118             }
119              
120 0           my ( $ip, $ident, $user, $ts, $request, $code, $size, $referer, $agent ) =
121             $msg =~ /^(\S+) (\S+) (\S+) \[([^\]]+)\] "([^"]+)" (\d+) (\d+) "([^"]+)" "([^"]+)"$/;
122 0 0         if( ! defined $ip ) {
123 0           return;
124             }
125 0           my $time;
126 0           eval { $time = Time::Piece->strptime($ts, "%d/%b/%Y:%H:%M:%S %z"); };
  0            
127 0           my ( $method, $uri, $proto ) = split(' ', $request );
128              
129 0           @$event{'client_ip', 'ident', 'user', 'time', 'method', 'uri', 'proto', 'code', 'size', 'referer', 'agent'}
130             = ( $ip, $ident, $user, $time, $method, $uri, $proto, $code, $size, $referer, $agent);
131              
132             # remove empty fields (content "-")
133 0           foreach my $key ( 'ident', 'user', 'referer' ) {
134 0 0         if( $event->{$key} eq '-' ) {
135 0           delete $event->{$key};
136             }
137             }
138              
139 0           return;
140             }
141              
142             1;
143              
144             __END__
145              
146             =pod
147              
148             =encoding UTF-8
149              
150             =head1 NAME
151              
152             Log::Saftpresse::Plugin::Apache - plugin to parse apache logs
153              
154             =head1 VERSION
155              
156             version 1.5
157              
158             =head1 AUTHOR
159              
160             Markus Benning <ich@markusbenning.de>
161              
162             =head1 COPYRIGHT AND LICENSE
163              
164             This software is Copyright (c) 1998 by James S. Seymour, 2015 by Markus Benning.
165              
166             This is free software, licensed under:
167              
168             The GNU General Public License, Version 2, June 1991
169              
170             =cut