File Coverage

blib/lib/Apache/ParseLog.pm
Criterion Covered Total %
statement 539 686 78.5
branch 229 364 62.9
condition 74 93 79.5
subroutine 53 83 63.8
pod 1 81 1.2
total 896 1307 68.5


line stmt bran cond sub pod time code
1             #######################################################################
2             # Apache::ParseLog
3             #
4             # Module to parse and process the Apache log files
5             #
6             # See the manpage for the usage
7             #
8             # Written by Akira Hangai
9             # For comments, suggestions, opinions, etc.,
10             # email to: akira@discover-net.net
11             #
12             # Copyright 1998 by Akira Hangai. All rights reserved.
13             # This program is free software; You can redistribute it and/or
14             # modify it under the same terms as Perl itself.
15             #######################################################################
16             package Apache::ParseLog;
17              
18             require 5.005;
19 9     9   23903 use Carp;
  9         17  
  9         937  
20 9     9   52 use vars qw($VERSION);
  9         16  
  9         112542  
21             $VERSION = "1.02";
22              
23             require Exporter;
24             @ISA = qw(Exporter);
25             @EXPORT = qw(countryByCode statusByCode sortHashByValue);
26             @EXPORT_OK = qw(countryByCode statusByCode sortHashByValue);
27              
28             =head1 NAME
29              
30             Apache::ParseLog - Object-oriented Perl extension for parsing Apache log files
31              
32             =head1 SYNOPSIS
33              
34             use Apache::ParseLog;
35             $base = new Apache::ParseLog();
36             $transferlog = $base->getTransferLog();
37             %dailytransferredbytes = $transferlog->bytebydate();
38             ...
39              
40             =head1 DESCRIPTION
41              
42             Apache::ParseLog provides an easy way to parse the Apache log files,
43             using object-oriented constructs. The data obtained using this module
44             are generic enough that it is flexible to use the data for your own
45             applications, such as CGI, simple text-only report generater, feeding
46             RDBMS, data for Perl/Tk-based GUI application, etc.
47              
48             =head1 FEATURES
49              
50             =over 4
51              
52             =item 1
53              
54             B
55              
56             Because all of the work (parsing logs, constructing regex, matching and
57             assigning to variables, etc.) is done inside this module, you can easily
58             create log reports (unless your logs need intense scrutiny). Read on this
59             manpage as well as the L<"EXAMPLES"> section to see how easy it is to
60             create log reports with this module.
61              
62             Also, this module does not require C compiler, and it can (should) run on
63             any platforms supported by Perl.
64              
65             =item 2
66              
67             B
68              
69             The Apache Web Server 1.3.x's new LogForamt/CustomLog feature (with
70             mod_log_config) is supported.
71              
72             The log format specified with Apache's F directive in the
73             F file will be parsed and the regular expressions will be
74             created dynamically inside this module, so re-writing your existing
75             code will be minimal when the log format is changed.
76              
77             =item 3
78              
79             B
80              
81             Tranditionally, the hit count is calculated based on the number of B
82             requested by visitors (the simplest is the the total number of lines of
83             the log file calculated as the "total hit").
84              
85             As such, the hit count obviously can be misleading in the sense of "how
86             many visitors have actually visited my site?", especially if the
87             pages of your site contain many images (because each image is counted as
88             one hit).
89              
90             Apache::ParseLog provides the methods to obtain such traditional data,
91             because those data also are very important for monitoring your web
92             site's activities. However, this module also provides the methods to
93             obtain the B, i.e., the actual number of "people"
94             (well, IP or hostname) who visited your site, by date, time, and date
95             and time.
96              
97             See the L<"LOG OBJECT METHODS"> for details about those methods.
98              
99             =item 4
100              
101             B
102              
103             The new pre-compiled regex feature introduced by Perl 5.005 is used (if
104             you have the version installed on your machine).
105              
106             For the pre-compiled regex and the new quote-like assignment operator (qr),
107             see perlop(1) and perlre(1) manpages.
108              
109             =back
110              
111             =cut
112              
113             #######################################################################
114             # Local variables
115             local($HOST, $LOGIN, $DATETIME, $REQUEST, $OSTATUS, $LSTATUS, $BYTE, $FILENAME, $ADDR, $PORT, $PROC, $SEC, $URL, $HOSTNAME, $REFERER, $UAGENT);
116              
117             my(%COUNTRY_BY_CODE) = map {
118             chomp;
119             my(@line) = split(/:/);
120             $line[0] => $line[1]
121             } ;
122              
123             my(%STATUS_BY_CODE) = (
124             100 => "Continue",
125             101 => "Switching Protocols",
126             200 => "OK",
127             201 => "Created",
128             202 => "Accepted",
129             203 => "Non-Authoritative Information",
130             204 => "No Content",
131             205 => "Reset Content",
132             206 => "Partial Content",
133             300 => "Multiple Choices",
134             301 => "Moved Permanently",
135             302 => "Moved Temporarily",
136             303 => "See Other",
137             304 => "Not Modified",
138             305 => "Use Proxy",
139             400 => "Bad Request",
140             401 => "Unauthorized",
141             402 => "Payment Required",
142             403 => "Forbidden",
143             404 => "Not Found",
144             405 => "Method Not Allowed",
145             406 => "Not Acceptable",
146             407 => "Proxy Authentication Required",
147             408 => "Request Time-out",
148             409 => "Conflict",
149             410 => "Gone",
150             411 => "Length Required",
151             412 => "Precondition Failed",
152             413 => "Request Entity Too Large",
153             414 => "Request-URI Too Large",
154             415 => "Unsupported Media Type",
155             500 => "Internal Server Error",
156             501 => "Not Implemented",
157             502 => "Bad Gateway",
158             503 => "Service Unavailable",
159             504 => "Gateway Time-out",
160             505 => "HTTP Version not supported",
161             );
162              
163             my(%M2N) = (
164             'Jan' => '01',
165             'Feb' => '02',
166             'Mar' => '03',
167             'Apr' => '04',
168             'May' => '05',
169             'Jun' => '06',
170             'Jul' => '07',
171             'Aug' => '08',
172             'Sep' => '09',
173             'Oct' => '10',
174             'Nov' => '11',
175             'Dec' => '12',
176             );
177              
178             #######################################################################
179             # Constructor
180             #######################################################################
181             =pod
182              
183             =head1 CONSTRUCTOR
184              
185             To construct an Apache::ParseLog object,B method is available
186             just like other modules.
187              
188             The C constructor returns an Apache::ParseLog base object with
189             which to obtain basic server information as well as to construct
190             B.
191              
192             =cut
193              
194             #######################################################################
195             # new([$path_to_httpd.conf]); returns ParseLog object
196             =pod
197              
198             =head2 New Method
199              
200             B>
201              
202             With the B> method, an Apache::ParseLog object can be created
203             in three different ways.
204              
205             =over 4
206              
207             =item 1
208              
209             C<$base = new Apache::ParseLog();>
210              
211             This first method creates an empty object, which means that the fields of
212             the object are undefined (C); i.e., the object does not know
213             what the server name is, where the log files are, etc. It is useful
214             when you need to parse log files that are B created on the local
215             Apache server (e.g., the log files FTP'd from elsewhere).
216              
217             You have to use the B> method (see below) to call any
218             other methods.
219              
220             =item 2
221              
222             C<$base = new Apache::ParseLog($httpd_conf);>
223              
224             This is the second way to create an object with necessary information
225             extracted from the I<$httpd_conf>. I<$httpd_conf> is a scalar string
226             containing the absolute path to the F file; e.g.,
227              
228             $httpd_conf = "/usr/local/httpd/conf/httpd.conf";
229              
230             This method tries to extract the information from I<$httpd_conf>,
231             specified by the following Apache directives:
232             F, F, F, F, F,
233             F, F, and any user-defined F along
234             with F.
235              
236             If any of the directives cannot be found or commented out in the
237             I<$httpd_conf>, then the field(s) for that directive(s) will be
238             empty (C), and corresponding methods that use the particular fields
239             return an empty string when called, or error out (for B
240             methods>, refer to the section below).
241              
242             =item 3
243              
244             C<$base = new Apache::ParseLog($httpd_conf, $virtual_host);>
245              
246             This method creates an object just like the second method, but for the
247             VirtualHost specified by I<$virtual_host> B. The Apache directives
248             and rules not specified within the and
249             tags are parsed from the "regular" server section in the F file.
250              
251             Note that the I<$httpd_conf> B be specified in order to create an
252             object for the I<$virtual_host>.
253              
254             =back
255              
256             =cut
257              
258             sub new {
259 10     10 0 59826 my($package) = shift;
260 10         151 my($httpd_conf) = shift;
261 10         141 my($virtual_host) = shift;
262 10         76 my(%ARG);
263 10         115 my($METHOD) = "Apache::ParseLog::new";
264 10 100       190 if (defined($httpd_conf)) {
265 8 50       704 unless (-e $httpd_conf) {
266 0         0 croak "$METHOD: $httpd_conf does not exist. Exiting...";
267             } else {
268 8         359 %ARG = populate($httpd_conf, $virtual_host);
269             }
270             }
271 10         125 return config($package, %ARG);
272             }
273              
274             #######################################################################
275             # BASE OBJECT METHODS
276             #######################################################################
277             =pod
278              
279             =head1 BASE OBJECT METHODS
280              
281             This section describes the methods available for the base object created
282             by the B> construct described above.
283              
284             Unless the object is created with an empty argument, the Apache::ParseLog
285             module parses the basic information configured in the F file
286             (as passed as the first argument). The object uses the information
287             to construct the B.
288              
289             The available methods are (return values are in parentheses):
290              
291             $base->config([%fields]); # (object)
292             $base->version(); # (scalar)
293             $base->serverroot(); # (scalar)
294             $base->servername(); # (scalar)
295             $base->httpport(); # (scalar)
296             $base->serveradmin(); # (scalar)
297             $base->transferlog(); # (scalar)
298             $base->errorlog(); # (scalar)
299             $base->agentlog(); # (scalar)
300             $base->refererlog(); # (scalar)
301             $base->customlog(); # (array)
302             $base->customlogLocation($name); # (scalar)
303             $base->customlogExists($name); # (scalar boolean, 1 or 0)
304             $base->customlogFormat($name); # (scalar)
305             $base->getTransferLog(); # (object)
306             $base->getErrorLog(); # (object)
307             $base->getRefererLog(); # (object)
308             $base->getAgentLog(); # (object)
309             $base->getCustomLog(); # (object)
310              
311             =over 4
312              
313             =cut
314              
315              
316             #######################################################################
317             # config($ParseLog, %arg); returns ParseLog object
318             =pod
319              
320             =item *
321              
322             C
323              
324             $base = $base->config(field1 => value1,
325             field2 => valud2,
326             fieldN => valueN);
327              
328             This method configures the Apache::ParseLog object. Possible fields are:
329              
330             Field Name Value
331             ---------------------------------------------------------
332             serverroot => absolute path to the server root directory
333             servername => name of the server, e.g., "www.mysite.com"
334             httpport => httpd port, e.g., 80
335             serveradmin => the administrator, e.g., "admin@mysite.com"
336             transferlog => absolute path to the transfer log
337             errorlog => absolute path to the error log
338             agentlog => absolute path to the agent log
339             refererlog => absolute path to the referer log
340              
341             This method should be called after the empty object is created
342             (C, see above). However, you can override the value(s) for any
343             fields by calling this method even if the object is created with defined
344             I<$httpd_conf> and I<$virtual_host>. (Convenient if you don't have any
345             httpd server running on your machine but have to parse the log files
346             transferred from elsewhere.)
347              
348             Any fields are optional, but at least one field should be specified
349             (otherwise why use this method?).
350              
351             When this method is called from the empty object, and B all the fields
352             are specified, the empty field still will be empty (thereby not being able
353             to use some corresponding methods).
354              
355             When this method is called from the already configured object (with
356             C), the fields specified in
357             this C method will override the existing field values, and
358             the rest of the fields inherit the pre-existing values.
359              
360             B This method B, so make sure
361             to use the assignment operator to create the new object
362             (see examples below).
363              
364             B You B (re)configure F values. It is to alleviate
365             the possible broken log formats, which would render the parsed results
366             unusable.
367              
368             Example 1
369              
370             # Create an empty object first
371             $base = new Apache::ParseLog();
372             # Configure the transfer and error fields only, for the files
373             # transferred from your Web site hosting service
374             $logs = "/home/webmaster/logs";
375             $base = $base->config(transferlog => "$logs/transfer_log",
376             errorlog => "$logs/error_log");
377              
378             Example 2
379              
380             # Create an object with $httpd_conf
381             $base = new Apache::ParseLog("/usr/local/httpd/conf/httpd.conf");
382             # Overrides some fields
383             $logs = "/usr/local/httpd/logs";
384             $base = $base->config(transferlog => "$logs/old/trans_199807",
385             errorlog => "$logs/old/error_199807",
386             agentlog => "$logs/old/agent_199807",
387             refererlog => "$logs/old/refer_199807");
388              
389             =cut
390              
391             sub config {
392 16     16 0 4115 my($this, %arg) = @_;
393 16         49 my($root, $servername, $port, $admin, $transfer, $error, $agent, $referer, %customlog);
394 16   100     178 $serverroot = $arg{'serverroot'} || $this->{'serverroot'};
395 16   100     127 $servername = $arg{'servername'} || $this->{'servername'};
396 16   100     228 $httpport = $arg{'httpport'} || $this->{'httpport'};
397 16   100     111 $serveradmin = $arg{'serveradmin'} || $this->{'serveradmin'};
398 16   100     111 $transferlog = $arg{'transferlog'} || $this->{'transferlog'};
399 16   100     143 $errorlog = $arg{'errorlog'} || $this->{'errorlog'};
400 16   100     116 $agentlog = $arg{'agentlog'} || $this->{'agentlog'};
401 16   100     111 $refererlog = $arg{'refererlog'} || $this->{'refererlog'};
402 16   100     87 $customlog = $arg{'customlog'} || $this->{'customlog'};
403 16         362 return bless {
404             'serverroot' => $serverroot,
405             'servername' => $servername,
406             'httpport' => $httpport,
407             'serveradmin' => $serveradmin,
408             'transferlog' => $transferlog,
409             'errorlog' => $errorlog,
410             'agentlog' => $agentlog,
411             'refererlog' => $refererlog,
412             'customlog' => $customlog,
413             }
414             }
415              
416             #######################################################################
417             # populate($path_to_httpd.conf[, $virtualHost]); return %arg; private
418             sub populate {
419 8     8 0 83 my($conf) = shift;
420 8         33 my($virtualhost) = shift;
421 8 100       72 my($VIRTUAL) = ($virtualhost ? 1 : 0);
422 8         36 my(%arg, $fh, $line, $serverroot, $servername, $httpport, $serveradmin, $transferlog, $errorlog, $agentlog, $refererlog, $customlog, @nickname, %location, %format);
423 8         133 $fh = openFile($conf);
424 8         368 while(defined($line = <$fh>)) {
425 327         964 chomp($line);
426 327 100       1533 if ($line =~ /^ServerRoot\s+(.+)$/) {
    100          
    100          
427 8         152 $serverroot = $1;
428             } elsif ($line =~ /^Port\s+(.+)$/) {
429 7         106 $httpport = $1;
430             } elsif ($line =~ /^LogFormat\s+"(.+)"\s+(\w+)$/) {
431 44         390 $format{$2} = $1;
432             }
433 327 100       651 unless ($VIRTUAL) { # check only when $VIRTUAL == 0
434 256 100       2023 if ($line =~ /^ServerName\s+(.+)$/) {
    100          
    100          
    100          
    100          
    100          
    100          
435 7         24 $servername = $1;
436             } elsif ($line =~ /^ServerAdmin\s+(.+)$/) {
437 7         99 $serveradmin = $1;
438             } elsif ($line =~ /^TransferLog\s+(.+)$/) {
439 6         20 $transferlog = $1;
440             } elsif ($line =~ /^ErrorLog\s+(.+)$/) {
441 7         28 $errorlog = $1;
442             } elsif ($line =~ /^AgentLog\s+(.+)$/) {
443 6         20 $agentlog = $1;
444             } elsif ($line =~ /^RefererLog\s+(.+)$/) {
445 6         19 $refererlog = $1;
446             } elsif ($line =~ /^CustomLog\s+(.+)\s+(\w+)$/) {
447 39         130 my($loc) = $1;
448 39         112 push(@nickname, $2);
449 39 50       170 if ($loc =~ m#\|#) { undef $loc }
  0 50       0  
450 39         99 elsif ($loc !~ m#^/#) { $loc = "$serverroot/$loc" }
451 39         130 $location{$2} = $loc;
452             }
453             }
454 327 100       645 if (defined($virtualhost)) {
455 46 100       451 if ($line =~ m#^#) {
    100          
456 1 50       80 if ($1 =~ /$virtualhost/i) { # if matches, 0
457 1         7 $VIRTUAL = 0;
458             }
459             } elsif ($line =~ m#^#) {
460 1         12 $VIRTUAL = 1; # if matches, 0
461             }
462             } else {
463 281 100       1445 if ($line =~ m#^
    100          
464 6         172 $VIRTUAL = 1;
465             } elsif ($line =~ m#^#) {
466 6         21 $VIRTUAL = 0;
467             }
468             }
469             }
470 8         169 close($fh);
471 8   50     58 $arg{'serverroot'} = $serverroot || undef;
472 8   100     170 $arg{'servername'} = $servername || undef;
473 8   100     68 $arg{'httpport'} = $httpport || undef;
474 8   100     60 $arg{'serveradmin'} = $serveradmin || undef;
475 8 100       29 if ($transferlog) {
476 6 50       47 if ($transferlog !~ m#^/#) {
    0          
477 6         27 $transferlog = "$serverroot/$transferlog"
478             } elsif ($transferlog =~ m#\|#) {
479 0         0 undef $transferlog
480             }
481             }
482 8         32 $arg{'transferlog'} = $transferlog;
483 8 100       62 if ($errorlog) {
484 7 50       43 if ($errorlog !~ m#^/#) {
    0          
485 7         37 $errorlog = "$serverroot/$errorlog"
486             } elsif ($errorlog =~ m#\|#) {
487 0         0 undef $errorlog
488             }
489             }
490 8         37 $arg{'errorlog'} = $errorlog;
491 8 100       54 if ($agentlog) {
492 6 50       25 if ($agentlog !~ m#^/#) {
    0          
493 6         20 $agentlog = "$serverroot/$agentlog"
494             } elsif ($agentlog =~ m#\|#) {
495 0         0 undef $agentlog
496             }
497             }
498 8         26 $arg{'agentlog'} = $agentlog;
499 8 100       54 if ($refererlog) {
500 6 50       23 if ($refererlog !~ m#^/#) {
    0          
501 6         20 $refererlog = "$serverroot/$refererlog"
502             } elsif ($refererlog =~ m#\|#) {
503 0         0 undef $refererlog
504             }
505             }
506 8         25 $arg{'refererlog'} = $refererlog;
507 8         226 $customlog = {
508             'nickname' => [ @nickname ],
509             'format' => { %format },
510             'location' => { %location },
511             };
512 8         50 $arg{'customlog'} = $customlog;
513 8         376 return %arg;
514             }
515              
516             #######################################################################
517             # serverroot(); returns $serverroot
518             =pod
519              
520             =item *
521              
522             C
523              
524             print $base->serverroot(), "\n";
525              
526             Returns a scalar containing the root of the Web server as specified
527             in the F file, or C if the object is not specified.
528              
529             =cut
530              
531             sub serverroot {
532 7     7 0 22 my($this) = shift;
533 7   50     59 return $this->{'serverroot'} || undef;
534             }
535              
536             #######################################################################
537             # servername(); returns $servername
538             =pod
539              
540             =item *
541              
542             C
543              
544             print $base->servername(), "\n";
545              
546             Returns a scalar containing the name of the Web server, or C
547             if server name is not specified.
548              
549             =cut
550              
551             sub servername {
552 2     2 0 821 my($this) = shift;
553 2   50     30 return $this->{'servername'} || undef;
554             }
555              
556             #######################################################################
557             # httpport(); returns $port
558             =pod
559              
560             =item *
561              
562             C
563              
564             print $base->httpport(), "\n";
565              
566             Returns a scalar containing the port number used for the httpd, or C
567             if not specified. (By default, httpd uses port 80.)
568              
569             =cut
570              
571             sub httpport {
572 1     1 0 10 my($this) = shift;
573 1   50     5 return $this->{'httpport'} || undef;
574             }
575              
576             #######################################################################
577             # serveradmin(); returns $serveradmin
578             =pod
579              
580             =item *
581              
582             C
583              
584             print $base->serveradmin(), "\n";
585              
586             Returns a scalar containing the name of the server administrator,
587             or C if not specified.
588              
589             =cut
590              
591             sub serveradmin {
592 2     2 0 43 my($this) = shift;
593 2   50     14 return $this->{'serveradmin'} || undef;
594             }
595              
596             #######################################################################
597             # transferlog(); returns $transferlog
598             =pod
599              
600             =item *
601              
602             C
603              
604             die "$!\n" unless -e $base->transferlog();
605              
606             Returns a scalar containing the absolute path to the transfer log file,
607             or C if not specified.
608              
609             =cut
610              
611             sub transferlog {
612 1     1 0 11 my($this) = shift;
613 1   50     4 return $this->{'transferlog'} || undef;
614             }
615              
616             #######################################################################
617             # errorlog(); returns $errorlog
618             =pod
619              
620             =item *
621              
622             C
623              
624             die "$!\n" unless -e $base->errorlog();
625              
626             Returns a scalar containing the absolute path to the error log file,
627             or C if not specified.
628              
629             =cut
630              
631             sub errorlog {
632 2     2 0 39 my($this) = shift;
633 2   50     26 return $this->{'errorlog'} || undef;
634             }
635              
636             #######################################################################
637             # agentlog(); returns $agentlog
638             =pod
639              
640             =item *
641              
642             C
643              
644             die "$!\n" unless -e $base->agentlog();
645              
646             Returns a scalar containing the absolute path to the agent log file,
647             or C if not specified.
648              
649             =cut
650              
651             sub agentlog {
652 1     1 0 15 my($this) = shift;
653 1   50     8 return $this->{'agentlog'} || undef;
654             }
655              
656             #######################################################################
657             # refererlog(); returns $refererlog
658             =pod
659              
660             =item *
661              
662             C
663              
664             die "$!\n" unless -e $base->refererlog();
665              
666             Returns a scalar containing the absolute path to the referer log file,
667             or C if not specified.
668              
669             =cut
670              
671             sub refererlog {
672 1     1 0 12 my($this) = shift;
673 1   50     7 return $this->{'refererlog'} || undef;
674             }
675              
676             #######################################################################
677             # customlog(); returns @customlog
678             =pod
679              
680             =item *
681              
682             C
683              
684             @customlog = $base->customlog();
685              
686             Returns an array containing "nicknames" of the custom logs defined in
687             the I<$httpd_conf>.
688              
689             =cut
690              
691             sub customlog {
692 8     8 0 38 my($this) = shift;
693 8         11 return @{ ${$this->{'customlog'}}{'nickname'} };
  8         1001  
  8         58  
694             }
695              
696             #######################################################################
697             # customlogDefined($customlog_nickname); returns 1 or 0; private
698             sub customlogDefined {
699 6     6 0 8 my($this) = shift;
700 6         8 my($nickname) = shift;
701 6         9 my($switch) = 0;
702 6         16 my(@logs) = customlog($this);
703 6         18 foreach (@logs) {
704 9 100       26 if ($_ eq $nickname) {
705 6         9 $switch++;
706 6         8 last;
707             }
708             }
709 6         22 return $switch;
710             }
711              
712             #######################################################################
713             # customlogLocation($customlog_nickname); returns path to the log
714             =pod
715              
716             =item *
717              
718             C
719              
720             print $base->customlogLocation($name), "\n";
721              
722             Returns a scalar containing the absolute path to the custom log I<$name>.
723             If the custom log I<$name> does not exist, it will return C.
724              
725             This method should be used for debugging purposes only, since you can call
726             C to parse the logs, making it unnecessary to manually open
727             the custom log file in your own script.
728              
729             =cut
730              
731             sub customlogLocation {
732 6     6 0 10 my($this) = shift;
733 6         9 my($nickname) = shift;
734 6         18 my($root) = serverroot($this);
735 6 50       16 if (customlogDefined($this, $nickname)) {
736 6         9 return ${ ${$this->{'customlog'}}{'location'} }{$nickname};
  6         7  
  6         148  
737             } else {
738 0         0 return undef;
739             }
740             }
741              
742             #######################################################################
743             # customlogExists($customlog_nickname); returns 1 or 0
744             =pod
745              
746             =item *
747              
748             C
749              
750             if ($base->customlogExists($name)) {
751             $customlog = $base->getCustomLog($name);
752             }
753              
754             Returns C<1> if the custom log I<$name> (e.g., B, B)
755             is defined in the I<$httpd_conf> file B the log file exists,
756             or C<0> otherwise.
757              
758             You do B have to call this method usually because this is internally
759             called by the C method.
760              
761             =cut
762              
763             sub customlogExists {
764 4     4 0 7 my($this) = shift;
765 4         8 my($nickname) = shift;
766 4         6 my($switch) = 0;
767 4 50       12 $switch++ if -e customlogLocation($this, $nickname);
768 4         20 return $switch;
769             }
770              
771             #######################################################################
772             # customlogFormat($customlog_nickname); returns the format
773             =pod
774              
775             =item *
776              
777             C
778              
779             print $base->customlogFormat($name), "\n";
780            
781             Returns a scalar containing the string of the "LogFormat" for the
782             custom log I<$name>, as specified in I<$httpd_conf>. This method
783             is meant to be used internally, as well as for debugging purpose.
784              
785             =cut
786              
787             sub customlogFormat {
788 2     2 0 5 my($this) = shift;
789 2         4 my($nickname) = shift;
790 2 50       6 if (customlogExists($this, $nickname)) {
791 2         3 return ${ ${$this->{'customlog'}}{'format'} }{$nickname};
  2         13  
  2         11  
792             } else {
793 0         0 return undef;
794             }
795             }
796              
797             #######################################################################
798             # getTransferLog(); returns a blessed ref object for TransferLog
799             =pod
800              
801             =item *
802              
803             C
804              
805             $transferlog = $base->getTransferLog();
806              
807             Returns an object through which to access the information
808             parsed from the F file. See the L<"LOG OBJECT METHODS"> below
809             for methods to access the log information.
810              
811             =cut
812              
813             sub getTransferLog {
814 2     2 0 320 my($this) = shift;
815 2         11 my($METHOD) = "Apache::ParseLog::getTransferLog";
816 2         7 my($logfile) = $this->{'transferlog'};
817 2 50       111 croak "$METHOD: $logfile does not exist. Exiting " unless -e $logfile;
818 2         15 my($FORMAT) = '(\\S+)\\s(\\S+)\\s(\\S+)\\s\\[(\\d{2}/\\w+/\\d{4}\\:\\d{2}\\:\\d{2}\\:\\d{2}\\s+.+?)\\]\\s\\"(\\w+\\s\\S+\\s\\w+\\/\\d+\\.\\d+)\\"\\s(\\d+)\\s(\\d+|-)';
819 2         11 my(@elements) = qw/HOST LOGIN USER DATETIME REQUEST LSTATUS BYTE/;
820 2         38 return scanLog($this, $logfile, $FORMAT, @elements);
821             }
822              
823             #######################################################################
824             # getRefererLog(); returns a blessed ref object for RefererLog
825             =pod
826              
827             =item *
828              
829             C
830              
831             $refererlog = $base->getRefererLog();
832              
833             Returns an object through which to access the information
834             parsed from the F file. See the L<"LOG OBJECT METHODS"> below
835             for methods to access the log information.
836              
837             =cut
838              
839             sub getRefererLog {
840 1     1 0 170 my($this) = shift;
841 1         6 my($METHOD) = "Apache::ParseLog::getRefererLog";
842 1         3 my($logfile) = $this->{'refererlog'};
843 1 50       31 croak "$METHOD: $logfile does not exist. Exiting " unless -e $logfile;
844 1         5 my($FORMAT) = '(\\S+)\\s\\-\\>\\s(\\S+)';
845 1         9 my(@elements) = qw/REFERER URL/;
846 1         20 return scanLog($this, $logfile, $FORMAT, @elements);
847             }
848              
849             #######################################################################
850             # getAgentLog(); returns a blessed ref object for AgentLog
851             =pod
852              
853             =item *
854              
855             C
856              
857             $agentlog = $base->getAgentLog();
858              
859             This method returns an object through which to access the information
860             parsed from the F file. See the L<"LOG OBJECT METHODS"> below
861             for methods to access the log information.
862              
863             =cut
864              
865             sub getAgentLog {
866 1     1 0 208 my($this) = shift;
867 1         6 my($METHOD) = "Apache::ParseLog::getAgentLog";
868 1         3 my($logfile) = $this->{'agentlog'};
869 1 50       41 croak "$METHOD: $logfile does not exist. Exiting " unless -e $logfile;
870 1         3 my($FORMAT) = '(.+)';
871 1         6 my(@elements) = qw/UAGENT/;
872 1         15 return scanLog($this, $logfile, $FORMAT, @elements);
873             }
874              
875             #######################################################################
876             # getErrorLog(); returns a blessed ref object for ErrorLog
877             =pod
878              
879             =item *
880              
881             C
882              
883             $errorlog = $base->getErrorLog();
884              
885             This method returns an object through which to access the information
886             parsed from the F file. See the L<"LOG OBJECT METHODS"> below
887             for methods to access the log information.
888              
889             =cut
890              
891             sub getErrorLog {
892 1     1 0 192 my($this) = shift;
893 1         5 my($METHOD) = "Apache::ParseLog::getErrorLog";
894 1         3 my($logfile) = $this->{'errorlog'};
895 1 50       28 croak "$METHOD: $logfile does not exist. Exiting " unless -e $logfile;
896 1         6 my($FORMAT) = '\\[(?:\\S+)\\s+(\\S+)\\s+(\\d+)\\s+(\\S+)\\s+(\\d{4})\\]\\s+(\\[(\\w+)\\])?';
897 1         41 my($regex) = qr/$FORMAT/;
898 1         2 my($line, %count, %allbydate, %allbytime, %allbydatetime, %allmessage, %errorbydate, %errorbytime, %errorbydatetime, %errormessage, %noticebydate, %noticebytime, %noticebydatetime, %noticemessage, %warnbydate, %warnbytime, %warnbydatetime, %warnmessage);
899 1         4 my($fh) = openFile($logfile);
900 1         29 while (defined($line = <$fh>)) {
901 68         77 chomp($line);
902 68 100       257 if ($line =~ m/^\[/) {
903 56         345 $line =~ m#$regex#;
904 56         120 my($m) = $M2N{$1};
905 56         75 my($d) = $2;
906 56         87 my($time) = $3;
907 56         79 my($y) = $4;
908 56         64 my($keyword) = $6;
909 56 100       155 $d = "0" . $d if $d =~ m/^\d$/;
910 56         104 my($date) = "$m/$d/$y";
911 56         175 $time =~ s/:.+$//;
912 56         92 my($datetime) = "$date-$time";
913 56         318 $line =~ s/^.+\]\s+//;
914 56 100       121 if ($keyword eq "error") {
    100          
    50          
915 44         58 $count{'error'}++;
916 44         56 $errorbydate{$date}++;
917 44         50 $errorbytime{$time}++;
918 44         57 $errorbydatetime{$datetime}++;
919 44         88 $errormessage{$line}++;
920             } elsif ($keyword eq "notice") {
921 3         8 $count{'notice'}++;
922 3         8 $noticebydate{$date}++;
923 3         5 $noticebytime{$time}++;
924 3         5 $noticebydatetime{$datetime}++;
925 3         9 $noticemessage{$line}++;
926             } elsif ($keyword eq "warn") {
927 9         12 $count{'warn'}++;
928 9         16 $warnbydate{$date}++;
929 9         12 $warnbytime{$time}++;
930 9         12 $warnbydatetime{$datetime}++;
931 9         21 $warnmessage{$line}++;
932             }
933 56         61 $allbydate{$date}++;
934 56         489 $allbytime{$time}++;
935 56         62 $allbydatetime{$datetime}++;
936 56 50       173 $allmessage{$line}++ if $line;
937 56         84 $count{'dated'}++;
938             } else {
939 12         13 $count{'nodate'}++;
940 12 50       34 $allmessage{$line}++ if $line;
941             }
942 68         346 $count{'Total'}++;
943             }
944 1         12 close($fh);
945 1         10 my(@methods) = qw/count allbydate allbytime allbydatetime allmessage errorbydate errorbytime errorbydatetime errormessage noticebydate noticebytime noticebydatetime noticemessage warnbydate warnbytime warnbydatetime warnmessage/;
946 1         140 return bless {
947             'allbydate' => { %allbydate },
948             'allbytime' => { %allbytime },
949             'allbydatetime' => { %allbydatetime },
950             'allmessage' => { %allmessage },
951             'errorbydate' => { %errorbydate },
952             'errorbytime' => { %errorbytime },
953             'errorbydatetime' => { %errorbydatetime },
954             'errormessage' => { %errormessage },
955             'noticebydate' => { %noticebydate },
956             'noticebytime' => { %noticebytime },
957             'noticebydatetime' => { %noticebydatetime },
958             'noticemessage' => { %noticemessage },
959             'warnbydate' => { %warnbydate },
960             'warnbytime' => { %warnbytime },
961             'warnbydatetime' => { %warnbydatetime },
962             'warnmessage' => { %warnmessage },
963             'count' => { %count },
964             'methods' => [ @methods ],
965             };
966             }
967              
968             #######################################################################
969             # getCustomLog($nickname); returns $customlog object
970             =pod
971              
972             =item *
973              
974             C
975              
976             $customlog = $base->getCustomLog($name);
977              
978             This method returns an object through which to access the information
979             parsed from the F file I<$name>. See the L<"LOG OBJECT METHODS">
980             below for methods for methods to access the log information.
981              
982             =back
983              
984             =cut
985              
986             sub getCustomLog {
987 2     2 0 372 my($this) = shift;
988 2         8 my($nickname) = shift;
989 2         8 my($METHOD) = "Apache::ParseLog::getCustomLog";
990 2 50       12 croak "$METHOD: $nickname does not exist, Exiting " unless customlogExists($this, $nickname);
991 2         5 my($logfile) = customlogLocation($this, $nickname);
992 2 50       46 croak "$METHOD: $logfile does not exist. Exiting " unless -e $logfile;
993             # Variables preparation
994 2         5 my($host_rx) = '(\\S+)'; # %h (host, visitor IP/hostname)
995 2         4 my($log_rx) = '(\\S+)'; # %l (login, login name)
996 2         4 my($user_rx) = '(\\S+)'; # %u (user, user name)
997 2         6 my($time_rx) = '\\[(\\d{2}/\\w+/\\d{4}\\:\\d{2}\\:\\d{2}\\:\\d{2}\\s+.+?)\\]'; # %t (datetime, date/time)
998 2         3 my($req_rx) = '(\\w+\\s\\S+\\s\\w+\\/\\d+\\.\\d+)';
999             # %r (request, method, file, proto)
1000 2         6 my($ost_rx) = '(\\d+)'; # %s (ostatus, original status)
1001 2         5 my($lst_rx) = '(\\d+)'; # %>s (lstatus, last status)
1002 2         3 my($byte_rx) = '(\\d+|-)'; # %b (byte, bytes)
1003 2         6 my($file_rx) = '(\\S+)'; # %f (filename, filename)
1004 2         9 my($addr_rx) = '(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})';
1005             # %a (addr, IP)
1006 2         4 my($port_rx) = '(\\d+)'; # %p (port, port)
1007 2         3 my($proc_rx) = '(\\d+)'; # %p (proc, proc ID)
1008 2         3 my($sec_rx) = '(\\d+)'; # %T (sec, time in sec)
1009 2         3 my($url_rx) = '(\\S+)'; # %U (url, URL)
1010 2         5 my($hname_rx) = '(\\S+)'; # %v (hostname, hostname)
1011 2         2 my($referer_rx) = '(\\S+)'; # %{Referer}i (referer, referer)
1012 2         3 my($uagent_rx) = '(.+?)'; # %{User-agent}i (uagent, browser)
1013 2         7 my($space) = '\\s'; # white space
1014 2         8 my($FORMAT) = customlogFormat($this, $nickname);
1015 2         8 my($temp) = $FORMAT . " "; # add the last space for the $temp regex below
1016 2         4 my(@regex, @elements);
1017             # Create the pre-compiled regex sting dynamically here
1018 2         8 while ((length($temp)) > 0) {
1019 20         115 $temp =~ s/^(\\?\")?(.+?)(\\?\")?\s+//;
1020 20         46 my($match) = $2;
1021 20 100       1351 if ($2 eq '%h') {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
1022 1         3 push(@regex, $host_rx); push(@elements, 'HOST');
  1         2  
1023             } elsif ($2 eq '%l') {
1024 1         3 push(@regex, $log_rx); push(@elements, 'LOGIN');
  1         3  
1025             } elsif ($2 eq '%u') {
1026 1         3 push(@regex, $user_rx); push(@elements, 'USER');
  1         2  
1027             } elsif ($2 eq '%t') {
1028 2         5 push(@regex, $time_rx); push(@elements, 'DATETIME');
  2         3  
1029             } elsif ($2 eq '%r') {
1030 1         3 push(@regex, $req_rx); push(@elements, 'REQUEST');
  1         2  
1031             } elsif ($2 eq '%s') {
1032 1         3 push(@regex, $ost_rx); push(@elements, 'OSTATUS');
  1         2  
1033             } elsif ($2 eq '%>s') {
1034 1         4 push(@regex, $lst_rx); push(@elements, 'LSTATUS');
  1         3  
1035             } elsif ($2 eq '%b') {
1036 1         10 push(@regex, $byte_rx); push(@elements, 'BYTE');
  1         2  
1037             } elsif ($2 eq '%f') {
1038 1         2 push(@regex, $file_rx); push(@elements, 'FILENAME');
  1         2  
1039             } elsif ($2 eq '%a') {
1040 1         2 push(@regex, $addr_rx); push(@elements, 'ADDR');
  1         3  
1041             } elsif ($2 eq '%p') {
1042 1         3 push(@regex, $port_rx); push(@elements, 'PORT');
  1         2  
1043             } elsif ($2 eq '%P') {
1044 1         3 push(@regex, $proc_rx); push(@elements, 'PROC');
  1         2  
1045             } elsif ($2 eq '%T') {
1046 1         3 push(@regex, $sec_rx); push(@elements, 'SEC');
  1         6  
1047             } elsif ($2 eq '%U') {
1048 2         4 push(@regex, $url_rx); push(@elements, 'URL');
  2         5  
1049             } elsif ($2 eq '%v') {
1050 1         4 push(@regex, $hname_rx); push(@elements, 'HOSTNAME');
  1         2  
1051             } elsif ($2 =~ /Referer/i) {
1052 1         3 push(@regex, $referer_rx); push(@elements, 'REFERER');
  1         3  
1053             } elsif ($2 =~ /User-agent/i) {
1054 1         3 push(@regex, $uagent_rx); push(@elements, 'UAGENT');
  1         2  
1055             } else {
1056 1         3 my($unknown) = $2;
1057 1         8 $unknown =~ s|(\W)|\\$1|g;
1058 1         3 push(@regex, $unknown);
1059             }
1060 20         536 $FORMAT =~ s/$match/$regex[$#regex]/;
1061             }
1062 2         22 $FORMAT =~ s/\s/$space/g;
1063             # Parse the log finally
1064 2         12 return scanLog($this, $logfile, $FORMAT, @elements);
1065             }
1066              
1067             #######################################################################
1068             # scanLog($path_to_logfile, $regex_format, @elments);
1069             # returns a blessed object; private
1070             sub scanLog {
1071 6     6 0 30 my($this) = shift; # package
1072 6         17 my($logfile) = shift; # path to the log
1073 6         14 my($FORMAT) = shift; # regex
1074 6         30 my(@elements) = @_; # array containing what's in the regex
1075             # create an array containing the uc name of placeholders
1076 6         16 my($hostswitch) = 1; # off with host defined
1077 6         13 my($visitorswitch) = 0; # on with host defined
1078 6         36 my($visitordone) = 0; # on with visitor added to @methods
1079 6         15 my($dtswitch) = 0; # on with datetime defined
1080 6         11 my($dtbyteswitch) = 0; # on with datetime or byte defined
1081 6         14 my($fileswitch) = 0; # on with filename or request or url defined
1082             my(@METHODS) = map {
1083 6 100 66     34 if ((m"^HOST") && ($hostswitch)) {
  36 100 100     1427  
    100 100        
    100 66        
    100 66        
    100 100        
    100 66        
    100          
1084 4         10 $hostswitch--;
1085 4         8 $visitorswitch++;
1086 4 100 66     22 if (($dtswitch) && (! $visitordone)) {
1087 1         4 ($_, "TOPDOMAIN", "SECDOMAIN", "VISITORBYDATE", "VISITORBYTTME", "VISITORBYDATETIME")
1088             } else {
1089 3         26 ($_, "TOPDOMAIN", "SECDOMAIN")
1090             }
1091             } elsif (((m"DATETIME") || (m"BYTE")) && (! $dtbyteswitch)) {
1092 4         8 $dtbyteswitch++;
1093 4 50       22 if (m"DATETIME") {
1094 4         8 $dtswitch++;
1095 4 100       12 if ($visitorswitch) {
1096 3         7 $visitorswitch = 0;
1097 3         5 $visitordone++;
1098 3         37 ("VISITORBYDATE", "VISITORBYTIME", "VISITORBYDATETIME", "HITBYDATE", "HITBYTIME", "HITBYDATETIME")
1099             } else {
1100 1         5 ("HITBYDATE", "HITBYTIME", "HITBYDATETIME")
1101             }
1102             } else {
1103 0         0 $_
1104             }
1105             } elsif (((m"DATETIME") || (m"BYTE")) && ($dtbyteswitch)) {
1106 3 50       12 if (m"DATETIME") {
1107 0         0 $dtswitch++;
1108 0 0       0 if ($visitorswitch) {
1109 0         0 $visitorswitch = 0;
1110 0         0 $visitordone++;
1111 0         0 ("VISITORBYDATE", "VISITORBYTIME", "VISITORBYDATETIME", "HITBYDATE", "HITBYTIME", "HITBYDATETIME", "BYTEBYDATE", "BYTEBYTIME", "BYTEBYDATETIME")
1112             } else {
1113 0         0 ("HITBYDATE", "HITBYTIME", "HITBYDATETIME", "BYTEBYDATE", "BYTEBYTIME", "BYTEBYDATETIME")
1114             }
1115             } else {
1116 3         27 ($_, "BYTEBYDATE", "BYTEBYTIME", "BYTEBYDATETIME")
1117             }
1118             } elsif (m"REQUEST") {
1119 3         8 $fileswitch++;
1120 3         30 ("METHOD", "FILE", "QUERYSTRING", "PROTO")
1121             } elsif ((m"FILENAME") || (m"URL")) {
1122 4         5 $fileswitch++;
1123 4         12 $_
1124             } elsif ((m"SEC") && ($fileswitch)) {
1125 1         3 $_
1126             } elsif (m"UAGENT") {
1127 2         22 ($_, "UAVERSION", "BROWSER", "PLATFORM", "BROWSERBYOS")
1128             } elsif (m"REFERER") {
1129 2         6 ($_, "REFERERDETAIL")
1130             } else {
1131 13         77 $_
1132             }
1133             } @elements;
1134 6         33 push(@METHODS, "HIT"); # the hit => { %hit } is always there
1135 6         14 @METHODS = map { lc } @METHODS;
  98         248  
1136             ### reports placeholders
1137 6         32 my(%host); # hosts (visitors)
1138             my(%topdomain); # top domains
1139 0         0 my(%secdomain); # secondary domains
1140 0         0 my(%login); # logins
1141 0         0 my(%user); # users
1142 0         0 my(%visitorbydate); # unique visitors (hosts) by date
1143 0         0 my(%visitorbytime); # unique visitors by time
1144 0         0 my(%visitorbydatetime); # unique visitors by date/time
1145 0         0 my(%hitbydate); # hits by date
1146 0         0 my(%hitbytime); # hits by time
1147 0         0 my(%hitbydatetime); # hits by date/time
1148 0         0 my(%method); # methods (get, post, etc.)
1149 0         0 my(%file); # files
1150 0         0 my(%querystring); # Query String
1151 0         0 my(%proto); # protos (HTTP/1.0, etc.)
1152 0         0 my(%ostatus); # original status (..)
1153 0         0 my(%lstatus); # last status (use with %STATUS_BY_CODE)
1154 0         0 my(%byte); # Bytes transferred (* containts one key "total")
1155 0         0 my(%bytebydate); # bytes by date
1156 0         0 my(%bytebytime); # bytes by time
1157 0         0 my(%bytebydatetime); # bytes by date/time
1158 0         0 my(%filename); # filenames (= files)
1159 0         0 my(%addr); # IPs (=~ hosts)
1160 0         0 my(%port); # ports
1161 0         0 my(%proc); # procs
1162 0         0 my(%sec); # seconds (time in sec)
1163 0         0 my(%url); # URLs (=~ files)
1164 0         0 my(%hostname); # hostnames (=~ hosts)
1165 0         0 my(%referer); # referer (site only)
1166 0         0 my(%refererdetail); # referer (detail)
1167 0         0 my(%uagent); # agents
1168 0         0 my(%uaversion); # uagent w/ versions (Mozilla/4.04, Slurp/2.0)
1169 0         0 my(%browser); # browsers w/ version
1170 0         0 my(%platform); # platforms only
1171 0         0 my(%browserbyos); # browsers w/ platforms
1172 0         0 my(%hit); # Total number of hits (lines)
1173             ### Routine
1174 6 100 66     46 if ((scalar(@elements) == 1) && ($elements[0] eq "UAGENT")) {
1175 1         4 $FORMAT =~ s#\?##
1176             }
1177 6         325 my($regex) = qr/$FORMAT/;
1178 6         13 my($line);
1179 6         29 my($fh) = openFile($logfile);
1180 6         223 while (defined($line = <$fh>)) {
1181 241         320 chomp($line);
1182 241         2629 $line =~ m#$regex#;
1183             # Scan each match
1184 241         5027 for ($i = 0; $i < scalar(@elements); $i++) {
1185 1142         1447 my($mi) = $i + 1; # index for match; $1, $2,...
1186 1142         1320 ${$elements[$i]} = ${$mi}; # assign the back ref
  1142         5231  
  1142         2739  
1187             }
1188 241         304 my($date, $time, $method, $file, $proto);
1189             ### create reports ###
1190             { # HOST RELATED BLOCK
1191             # HOST
1192 241 100       250 $host{$HOST}++ if $HOST;
  241         508  
1193             # HOSTNAME
1194 241 100       467 $hostname{$HOSTNAME}++ if $HOSTNAME;
1195 241 100       459 my($domain) = ($HOST ? $HOST : $HOSTNAME);
1196             # (TOP|SEC)DOMAIN
1197 241 100       507 if ($domain) {
1198 118 50       296 if ($domain !~ /^\d{1,3}(?:\.\d{1,3}){3}$/) {
1199 118 50       535 if ($domain =~ m/\.([A-Za-z0-9\-]+\.)(\w+)$/) {
1200 118         220 my($secdomain) = $1;
1201 118         181 my($topdomain) = $2;
1202 118         183 $topdomain{$topdomain}++;
1203 118         157 $secdomain = $secdomain . $topdomain;
1204 118         256 $secdomain{$secdomain}++;
1205             } else {
1206 0         0 $topdomain{$domain}++;
1207 0         0 $secdomain{$domain}++;
1208             }
1209             } else {
1210 0         0 $topdomain{'unknown'}++;
1211 0         0 $secdomain{'unknown'}++;
1212             }
1213             }
1214             }
1215             # LOGIN
1216 241 100       593 $login{$LOGIN}++ if $LOGIN;
1217             # USER
1218 241 100       490 $user{$USER}++ if $USER;
1219             # DATETIME
1220 241 100       449 if ($DATETIME) {
1221 118         485 $DATETIME =~ m#^(\d+)/(\w+)/(\d+)\:(\d{2})\:\d{2}\:\d{2}#;
1222 118 50       422 my($d) = ($1 =~ /^\d$/ ? '0' . $1 : $1);
1223 118         247 my($m) = $M2N{$2};
1224 118         187 my($y) = $3;
1225 118         246 my($t) = $4;
1226 118         251 my($date) = "$m/$d/$y";
1227 118         191 $hitbydate{$date}++;
1228 118         170 $hitbytime{$t}++;
1229 118         199 my($dt) = "$date-$t";
1230 118         176 $hitbydatetime{$dt}++;
1231 118 100 100     732 if (($BYTE) && ($BYTE =~ m#^\d+$#)) {
1232 68         139 $bytebydate{$date} += $BYTE;
1233 68         94 $bytebytime{$t} += $BYTE;
1234 68         119 $bytebydatetime{$dt} += $BYTE;
1235             }
1236 118         140 my($visitor);
1237 118 100       236 if ($HOST) { $visitor = $HOST }
  89 50       130  
    0          
1238 29         41 elsif ($HOSTNAME) { $visitor = $HOSTNAME }
1239 0         0 elsif ($ADDR) { $visitor = $HOSTNAME }
1240 118         132 ${$date}{$visitor}++;
  118         347  
1241 118         155 ${$t}{$visitor}++;
  118         604  
1242 118         167 ${$dt}{$visitor}++;
  118         435  
1243             }
1244             # STATUS
1245 241 100       541 if ($OSTATUS) {
1246 29         58 my($key) = "$OSTATUS $STATUS_BY_CODE{$OSTATUS}";
1247 29         40 $ostatus{$key}++;
1248             }
1249 241 100       446 if ($LSTATUS) {
1250 89         271 my($key) = "$LSTATUS $STATUS_BY_CODE{$LSTATUS}";
1251 89         149 $lstatus{$key}++;
1252             }
1253             # FILENAME
1254 241 100       500 $filename{$FILENAME}++ if $FILENAME;
1255             # ADDR
1256 241 100       423 $addr{$ADDR}++ if $ADDR;
1257             # PORT
1258 241 100       413 $port{$PORT}++ if $PORT;
1259             # PROC
1260 241 100       550 $proc{$PROC}++ if $PROC;
1261             { # BEGIN FILE RELATED BLOCK
1262 241         235 my($FILE);
  241         269  
1263             # REQUEST
1264 241 100       1592 if ($REQUEST) {
1265 89         325 $REQUEST =~ m#^(\w+)\s(\S+)\s(\S+)$#;
1266 89         170 my($method) = $1;
1267 89         146 my($file) = $2;
1268 89         140 my($proto) = $3;
1269 89         126 $method{$method}++;
1270 89 50       226 if ($file =~ m#\?(.+)$#) {
1271 0         0 $querystring{$1}++; # query string
1272             }
1273 89         156 $file =~ s#\?.+$##; # trim query_string
1274 89         124 $file =~ s#/\./#/#g; # same-dir duplicates
1275 89         119 $file =~ s#/\s+?/\.\./#/#g; # same-upper-dir duplicates
1276 89         185 $file{$file}++;
1277 89         127 $proto{$proto}++;
1278 89         165 $FILE = $file;
1279             }
1280             # URL
1281 241 100       478 if ($URL) {
1282 88         181 $url{$URL}++;
1283 88         119 $FILE = $URL;
1284             }
1285             # FILE
1286 241 100       462 $FILE = $FILENAME unless $FILE;
1287             # SEC
1288 241 100       999 SEC: if ($SEC) {
1289 8 50       14 last SEC unless $FILE;
1290 8 50       17 if (exists($sec{$FILE})) {
1291 0 0       0 $sec{$FILE} = "$SEC" if $SEC > $sec{$FILE};
1292             } else {
1293 8         20 $sec{$FILE} = "$SEC";
1294             }
1295             }
1296             # BYTE
1297 241 100 100     894 if (($BYTE) && ($BYTE =~ m#^\d+$#)) {
1298 68         118 $byte{'Total'} += $BYTE;
1299 68 50       136 last unless $FILE;
1300 68         178 $FILE =~ m#\.(\w+)$#;
1301 68 100       164 if ($1) {
1302 48         82 $byte{$1} += $BYTE;
1303 48         81 $hit{$1}++;
1304             } else {
1305 20         41 $byte{'OtherTypes'} += $BYTE;
1306 20         37 $hit{'OtherTypes'}++;
1307             }
1308             }
1309             # REFERER
1310 241 100       583 if ($REFERER) {
1311 59         56 my($refered);
1312 59 50       95 if ($URL) { $refered = $URL }
  59 0       76  
    0          
1313 0         0 elsif ($FILE) { $refered = $FILE }
1314 0         0 elsif ($FILENAME) { $refered = $FILENAME }
1315 59 50       151 my($ref) = (($refered) ? "$REFERER -> $refered" : $REFERER);
1316 59         202 $refererdetail{$ref}++;
1317 59 100       1372 if ($REFERER =~ m#http://(\S+?)[/?]#) { $referer{$1}++ }
  52 50       137  
1318 7         17 elsif ($REFERER =~ m#^-$#) { $referer{'bookmark'}++ }
1319 0         0 else { $referer{'unknown'}++ }
1320             }
1321             } # END FILE RELATED BLOCK
1322             # UAGENT
1323 241 100       436 if ($UAGENT) {
1324 120         246 $uagent{$UAGENT}++;
1325 120         370 $UAGENT =~ m#^(\S+)\s*(.+)?$#;
1326 120         211 my($parser) = $1;
1327 120         172 my($rest) = $2;
1328 120 50       247 $uaversion{$parser}++ if $parser;
1329 120         112 my($browser);
1330 120 100 100     1849 if (($UAGENT =~ m/^Mozilla/)
    50 33        
      33        
1331             && (($rest =~ m/(Webtv.+?)[;)]/)
1332             || ($rest =~ m/(AOL.+?)[;)]/)
1333             || ($rest =~ m/(MSN.+?)[;)]/)
1334             || ($rest =~ m/(MSIE.+?)[;)]/))) {
1335 19         47 $browser = $1;
1336 19         51 $browser{$1}++;
1337             } elsif (($UAGENT =~ m/Mozilla/) && ($rest =~ m/compatible\;\s+(.+?)[;)]/)) {
1338 0         0 $browser = $1;
1339 0         0 $browser{$1}++;
1340             } else {
1341 101         120 $browser = $parser;
1342 101         148 $browser{$browser}++;
1343             }
1344 120         173 my($plat);
1345 120 100       526 if ($rest =~ m/(Win.+?)[;)]/) {
    100          
    100          
1346 75         99 $plat = $1;
1347 75         119 $platform{$1}++;
1348             } elsif ($rest =~ m/(Mac.+?)[;)]/) {
1349 9         13 $plat = $1;
1350 9         13 $platform{$1}++;
1351             } elsif ($rest =~ m/X11\;\s+.+?\;\s+(.+?)[;)]/) {
1352 34         61 $plat = $1;
1353 34         67 $platform{$1}++;
1354             } else {
1355 2         3 $plat = $rest;
1356 2         23 $plat =~ s#(?:\(|\)|\;)##g;
1357 2         6 $platform{$plat}++;
1358             }
1359 120         206 my($bandp) = "$browser ($plat)";
1360 120         246 $browserbyos{$bandp}++;
1361             }
1362             # hit
1363 241         1286 $hit{'Total'}++;
1364             }
1365 6         124 close($fh);
1366             # Construct %visitorxxx hashes
1367 6         44 %visitorbydate = map { $_ => scalar(keys %{$_}), } keys %hitbydate;
  12         20  
  12         58  
1368 6         27 %visitorbytime = map { $_ => scalar(keys %{$_}), } keys %hitbytime;
  14         20  
  14         59  
1369 6         70 %visitorbydatetime = map { $_ => scalar(keys %{$_}), } keys %hitbydatetime;
  20         24  
  20         76  
1370 6         1781 return bless {
1371             'host' => { %host },
1372             'topdomain' => { %topdomain },
1373             'secdomain' => { %secdomain },
1374             'login' => { %login },
1375             'user' => { %user },
1376             'hitbydate' => { %hitbydate },
1377             'hitbytime' => { %hitbytime },
1378             'hitbydatetime' => { %hitbydatetime },
1379             'visitorbydate' => { %visitorbydate },
1380             'visitorbytime' => { %visitorbytime },
1381             'visitorbydatetime' => { %visitorbydatetime },
1382             'method' => { %method },
1383             'file' => { %file },
1384             'querystring' => { %querystring },
1385             'proto' => { %proto },
1386             'ostatus' => { %ostatus },
1387             'lstatus' => { %lstatus },
1388             'byte' => { %byte },
1389             'bytebydate' => { %bytebydate },
1390             'bytebytime' => { %bytebytime },
1391             'bytebydatetime' => { %bytebydatetime },
1392             'filename' => { %filename },
1393             'addr' => { %addr },
1394             'port' => { %port },
1395             'proc' => { %proc },
1396             'sec' => { %sec },
1397             'url' => { %url },
1398             'hostname' => { %hostname },
1399             'referer' => { %referer },
1400             'refererdetail' => { %refererdetail },
1401             'uagent' => { %uagent },
1402             'uaversion' => { %uaversion },
1403             'browser' => { %browser },
1404             'platform' => { %platform },
1405             'browserbyos' => { %browserbyos },
1406             'hit' => { %hit },
1407             'methods' => [ @METHODS ],
1408             };
1409             }
1410              
1411             #######################################################################
1412             # LOG OBJECT METHODS
1413             #######################################################################
1414             =pod
1415              
1416             =head1 LOG OBJECT METHODS
1417              
1418             This section describes the methods available for the log object created
1419             by any of the following base object methods: B,
1420             B, B, B, and
1421             B.
1422              
1423             This section is devided into six subsections, each of which describes
1424             the available methods for a certain log object.
1425              
1426             Note that all the methods for F, F, and F
1427             can be used for the object created with C.
1428              
1429             =cut
1430              
1431             #######################################################################
1432             # TRANSFERLOG METHODS
1433             =pod
1434              
1435             =head2 TransferLog/CustomLog Methods
1436              
1437             The following methods are available for the F object
1438             (created by C method), as well as the F
1439             object that logs appropriate arguments to the corresponding F.
1440              
1441             =over 4
1442              
1443             =cut
1444              
1445             ######################################################################
1446             # hit(); returns %hit
1447             =pod
1448              
1449             =item *
1450              
1451             C
1452              
1453             %hit = $logobject->hit();
1454              
1455             Returns a hash containing at least a key 'Total' with the total
1456             hit count as its value, and the file extensions (i.e., html,
1457             jpg, gif, cgi, pl, etc.) as keys with the hit count for each key as
1458             values.
1459              
1460             =cut
1461              
1462             sub hit {
1463 1     1 0 369 my($this) = shift;
1464 1 50       3 return %{($this->{'hit'} || undef)};
  1         14  
1465             }
1466              
1467             #######################################################################
1468             # host(); returns %host
1469             =pod
1470              
1471             =item *
1472              
1473             C
1474              
1475             %host = $logobject->host();
1476              
1477             Returns a hash containing host names (or IPs if names are unresolved)
1478             of the visitors as keys, and the hit count for each key as values.
1479              
1480             =cut
1481              
1482             sub host {
1483 1     1 0 201 my($this) = shift;
1484 1 50       4 my(%host) = %{($this->{'host'} || undef)};
  1         11  
1485 1         8 return %host;
1486             }
1487              
1488             #######################################################################
1489             # topdomain(); returns %topdomain
1490             =pod
1491              
1492             =item *
1493              
1494             C
1495              
1496             %topdomain = $logobject->topdomain();
1497              
1498             Returns a hash containing topdomain names (com, net, etc.) of the
1499             visitors as keys, and the hit count for each key as values.
1500              
1501             Note that if the hostname is unresolved and remains as an IP address,
1502             the visitor will not be counted toward the (and the next C)
1503             returned value of this method.
1504              
1505             =cut
1506              
1507             sub topdomain {
1508 0     0 0 0 my($this) = shift;
1509 0 0       0 return %{($this->{'topdomain'} || undef)};
  0         0  
1510             }
1511              
1512             ######################################################################
1513             # secdomain(); returns %secdomain
1514             =pod
1515              
1516             =item *
1517              
1518             C
1519              
1520             %secdomain = $logobject->secdomain();
1521              
1522             Returns a hash containing secondary domain names (xxx.com, yyy.net,
1523             etc.) as keys, and the hit count for each key as values.
1524              
1525             For the unresolved IPs, the same rule applies as the above C
1526             method.
1527              
1528             =cut
1529              
1530             sub secdomain {
1531 0     0 0 0 my($this) = shift;
1532 0 0       0 return %{($this->{'secdomain'} || undef)};
  0         0  
1533             }
1534              
1535             ######################################################################
1536             # login(); returns %login
1537             =pod
1538              
1539             =item *
1540              
1541             C
1542              
1543             %login = $logobject->login();
1544              
1545             Returns a hash containing login names (authenticated user logins)
1546             of the visitors as keys, and the hit count for each key as values.
1547              
1548             Log entries for non-authenticated files have a character "-" as the
1549             login name.
1550              
1551             =cut
1552              
1553             sub login {
1554 0     0 0 0 my($this) = shift;
1555 0 0       0 return %{($this->{'login'} || undef)};
  0         0  
1556             }
1557              
1558             ######################################################################
1559             # user(); returns %user
1560             =pod
1561              
1562             =item *
1563              
1564             C
1565              
1566             %user = $logobject->user();
1567              
1568             Returns a hash containing user names (for access-controlled directories,
1569             refer to the access.conf file of the Apache server) of the visitors as
1570             keys, and the hit count for each key as values.
1571              
1572             Non-access-controlled log entries have a character "-" as the user name.
1573              
1574             =cut
1575              
1576             sub user {
1577 1     1 0 178 my($this) = shift;
1578 1 50       3 return %{($this->{'user'} || undef)};
  1         9  
1579             }
1580              
1581             ######################################################################
1582             # hitbydate(); returns %hitbydate
1583             =pod
1584              
1585             =item *
1586              
1587             C
1588              
1589             %hitbydate = $logobject->hitbydate();
1590              
1591             Returns a hash containing date (mm/dd/yyyy) when visitors visited the
1592             particular file (html, jpg, etc.) as keys, and the hit count
1593             for each key as values.
1594              
1595             =cut
1596              
1597             sub hitbydate {
1598 1     1 0 392 my($this) = shift;
1599 1 50       3 return %{($this->{'hitbydate'} || undef)};
  1         11  
1600             }
1601              
1602             ######################################################################
1603             # hitbytime(); returns %hitbytime
1604             =pod
1605              
1606             =item *
1607              
1608             C
1609              
1610             %hitbytime = $logobject->hitbytime();
1611              
1612             Returns a hash containing time (00-23) each file was visited as keys,
1613             and the hit count for each key as values.
1614              
1615             =cut
1616              
1617             sub hitbytime {
1618 0     0 0 0 my($this) = shift;
1619 0 0       0 return %{($this->{'hitbytime'} || undef)};
  0         0  
1620             }
1621              
1622             ######################################################################
1623             # hitbydatetime(); returns %hitbydatetime
1624             =pod
1625              
1626             =item *
1627              
1628             C
1629              
1630             %hitbydatetime = $logobject->hitbydatetime();
1631              
1632             Returns a hash containing date/time (mm/dd/yyyy-hh)
1633             as keys, and the hit count for each key as values.
1634              
1635             =cut
1636              
1637             sub hitbydatetime {
1638 0     0 0 0 my($this) = shift;
1639 0 0       0 return %{($this->{'hitbydatetime'} || undef)};
  0         0  
1640             }
1641              
1642             ######################################################################
1643             # visitorbydate(); returns %visitorbydate
1644             =pod
1645              
1646             =item *
1647              
1648             C
1649              
1650             %visitorbydate = $logobject->visitorbydate();
1651              
1652             Returns a hash containing date (mm/dd/yyyy) as keys, and the unique
1653             visitor count for each key as values.
1654              
1655             =cut
1656              
1657             sub visitorbydate {
1658 1     1 0 139 my($this) = shift;
1659 1 50       2 return %{($this->{'visitorbydate'} || undef)};
  1         7  
1660             }
1661              
1662             ######################################################################
1663             # visitorbytime(); returns %visitorbytime
1664             =pod
1665              
1666             =item *
1667              
1668             C
1669              
1670             %visitorbytime = $logobject->visitorbytime();
1671              
1672             Returns a hash containing time (00-23) as keys, and the unique visitor
1673             count for each key as values.
1674              
1675             =cut
1676              
1677             sub visitorbytime {
1678 0     0 0 0 my($this) = shift;
1679 0 0       0 return %{($this->{'visitorbytime'} || undef)};
  0         0  
1680             }
1681              
1682             ######################################################################
1683             # visitorbydatetime(); returns %visitorbydatetime
1684             =pod
1685              
1686             =item *
1687              
1688             C
1689              
1690             %visitorbydatetime = $logobject->visitorbydatetime();
1691              
1692             Returns a hash containing date/time (mm/dd/yyyy-hh)
1693             as keys, and the unique visitor count for each key as values.
1694              
1695             =cut
1696              
1697             sub visitorbydatetime {
1698 0     0 0 0 my($this) = shift;
1699 0 0       0 return %{($this->{'visitorbydatetime'} || undef)};
  0         0  
1700             }
1701              
1702             ######################################################################
1703             # method(); returns %method
1704             =pod
1705              
1706             =item *
1707              
1708             C
1709              
1710             %method = $logobject->method();
1711              
1712             Returns a hash containing HTTP method (GET, POST, PUT, etc.)
1713             as keys, and the hit count for each key as values.
1714              
1715             =cut
1716              
1717             sub method {
1718 0     0 0 0 my($this) = shift;
1719 0 0       0 return %{($this->{'method'} || undef)};
  0         0  
1720             }
1721              
1722             ######################################################################
1723             # file(); returns %file
1724             =pod
1725              
1726             =item *
1727              
1728             C
1729              
1730             %file = $logobject->file();
1731              
1732             Returns a hash containing the file names relative to the F
1733             of the server as keys, and the hit count for each key as values.
1734              
1735             =cut
1736              
1737             sub file {
1738 1     1 0 120 my($this) = shift;
1739 1 50       1 return %{($this->{'file'} || undef)};
  1         13  
1740             }
1741              
1742             ######################################################################
1743             # querystring(); returns %querystring
1744             =pod
1745              
1746             =item *
1747              
1748             C
1749              
1750             %querystring = $logobject->querystring();
1751              
1752             Returns a hash containing the query string
1753             as keys, and the hit count for each key as values.
1754              
1755             =cut
1756              
1757             sub querystring {
1758 0     0 0 0 my($this) = shift;
1759 0 0       0 return %{($this->{'querystring'} || undef)};
  0         0  
1760             }
1761              
1762             ######################################################################
1763             # proto(); returns %proto
1764             =pod
1765              
1766             =item *
1767              
1768             C
1769              
1770             %proto = $logobject->proto();
1771              
1772             Returns a hash containing the protocols used (HTTP/1.0, HTTP/1.1, etc.)
1773             as keys, and the hit count for each key as values.
1774              
1775             =cut
1776              
1777             sub proto {
1778 0     0 0 0 my($this) = shift;
1779 0 0       0 return %{($this->{'proto'} || undef)};
  0         0  
1780             }
1781              
1782             ######################################################################
1783             # lstatus(); returns %lstatus
1784             =pod
1785              
1786             =item *
1787              
1788             C
1789              
1790             %lstatus = $logobject->lstatus();
1791              
1792             Returns a hash containing HTTP codes and messages (e.g. "404 Not Found")
1793             for the last status (i.e., when the httpd finishes processing that
1794             request) as keys, and the hit count for each key as values.
1795              
1796             =cut
1797              
1798             sub lstatus {
1799 1     1 0 123 my($this) = shift;
1800 1 50       2 return %{($this->{'lstatus'} || undef)};
  1         14  
1801             }
1802              
1803             ######################################################################
1804             # byte(); returns %byte
1805             =pod
1806              
1807             =item *
1808              
1809             C
1810              
1811             %byte = $logobject->byte();
1812              
1813             Returns a hash containing at least a key 'Total' with the total
1814             transferred bytes as its value, and the file extensions (i.e., html,
1815             jpg, gif, cgi, pl, etc.) as keys, and the transferred bytes for each
1816             key as values.
1817              
1818             =cut
1819              
1820             sub byte {
1821 1     1 0 140 my($this) = shift;
1822 1 50       2 return %{($this->{'byte'} || undef)};
  1         10  
1823             }
1824              
1825             ######################################################################
1826             # bytebydate(); returns %bytebydate
1827             =pod
1828              
1829             =item *
1830              
1831             C
1832              
1833             %bytebydate = $logobject->bytebydate();
1834              
1835             Returns a hash containing date (mm/dd/yyyy) as keys, and the hit
1836             count for each key as values.
1837              
1838             =cut
1839              
1840             sub bytebydate {
1841 0     0 0 0 my($this) = shift;
1842 0 0       0 return %{($this->{'bytebydate'} || undef)};
  0         0  
1843             }
1844              
1845             ######################################################################
1846             # bytebytime(); returns %bytebytime
1847             =pod
1848              
1849             =item *
1850              
1851             C
1852              
1853             %bytebytime = $logobject->bytebytime();
1854              
1855             Returns a hash containing time (00-23) as keys, and the hit count
1856             for each key as values.
1857              
1858             =cut
1859              
1860             sub bytebytime {
1861 0     0 0 0 my($this) = shift;
1862 0 0       0 return %{($this->{'bytebytime'} || undef)};
  0         0  
1863             }
1864              
1865             ######################################################################
1866             # bytebydatetime(); returns %bytebydatetime
1867             =pod
1868              
1869             =item *
1870              
1871             C
1872              
1873             %bytebydatetime = $logobject->bytebydatetime();
1874              
1875             Returns a hash containing date/time (mm/dd/yyyy-hh) as keys, and the
1876             hit count for each key as values.
1877              
1878             =back
1879              
1880             =cut
1881              
1882             sub bytebydatetime {
1883 0     0 0 0 my($this) = shift;
1884 0 0       0 return %{($this->{'bytebydatetime'} || undef)};
  0         0  
1885             }
1886              
1887             #######################################################################
1888             # ERRORLOG METHODS
1889             =pod
1890              
1891             =head2 ErrorLog Methods
1892              
1893             Until the Apache version 1.2.x, each error log entry was just an error,
1894             meaning that there was no distinction between "real" errors (e.g., File
1895             Not Found, malfunctioning CGI, etc.) and non-significant errors (e.g.,
1896             kill -1 the httpd processes, etc.).
1897              
1898             Starting from the version 1.3.x, the Apache httpd logs the "type" of
1899             each error log entry, namely "error", "notice" and "warn".
1900              
1901             If you use Apache 1.2.x, the C, C,
1902             and C should not be used, because those methods for
1903             that are for 1.3.x only will merely return an empty hash.
1904             The C methods will return desired results.
1905              
1906             The following methods are available for the F object
1907             (created by C method).
1908              
1909             =over 4
1910              
1911             =cut
1912              
1913             #######################################################################
1914             # total(); returns $total;
1915             =pod
1916              
1917             =item *
1918              
1919             C
1920              
1921             %errors = $errorlogobject->count();
1922              
1923             Returns a hash containing count for each type of messages
1924             logged in the error log file.
1925              
1926             The keys and values are: 'Total' (total number of errors), 'error'
1927             (total number of errors of type "error"), 'notice' total number of
1928             errors of type "notice"), 'warn' (total number of errors of type
1929             "warn"), 'dated' (total number of error entries with date logged),
1930             and 'nodate' (total number of error entires with no date logged).
1931             So:
1932              
1933             print "Total Errors: ", $errors{'Total'}, "\n";
1934             print "Total 1.3.x Errors: ", $errors{'error'}, "\n";
1935             print "Total 1.3.x Notices: ", $errors{'notice'}, "\n";
1936             print "Total 1.3.x Warns: ", $errors{'warn'}, "\n";
1937             print "Total Errors with date: ", $errors{'dated'}, "\n";
1938             print "Total Errors with no date: ", $errors{'nodate'}, "\n";
1939              
1940             Note that with the F file generated by Apache version
1941             before 1.3.x, the value for 'error', 'notice', and 'warn' will
1942             be zero.
1943              
1944             =cut
1945              
1946             sub count {
1947 1     1 0 229 my($this) = shift;
1948 1 50       2 return %{($this->{'count'} || undef)};
  1         12  
1949             }
1950              
1951             #######################################################################
1952             # allbydate(); returns %allbydate;
1953             =pod
1954              
1955             =item *
1956              
1957             C
1958              
1959             %allbydate = $errorlogobject->allbydate();
1960              
1961             Returns a hash containing date (mm/dd/yyyy) when the error was logged
1962             as keys, and the number of error occurrances as values.
1963              
1964             =cut
1965              
1966             sub allbydate {
1967 1     1 0 167 my($this) = shift;
1968 1 50       2 return %{($this->{'allbydate'} || undef)};
  1         100  
1969             }
1970              
1971             #######################################################################
1972             # allbytime(); returns %allbytime;
1973             =pod
1974              
1975             =item *
1976              
1977             C
1978              
1979             %allbytime = $errorlogobject->allbytime();
1980              
1981             Returns a hash containing time (00-23) as keys and the number
1982             of error occurrances as values.
1983              
1984             =cut
1985              
1986             sub allbytime {
1987 0     0 0 0 my($this) = shift;
1988 0 0       0 return %{($this->{'allbytime'} || undef)};
  0         0  
1989             }
1990              
1991             #######################################################################
1992             # allbydatetime(); returns %allbydatetime;
1993             =pod
1994              
1995             =item *
1996              
1997             C
1998              
1999             %allbydatetime = $errorlogobject->allbydatetime();
2000              
2001             Returns a hash containing date/time (mm/dd/yyyy-hh) as keys and the
2002             number of error occurrances as values.
2003              
2004             =cut
2005              
2006             sub allbydatetime {
2007 0     0 0 0 my($this) = shift;
2008 0 0       0 return %{($this->{'allbydatetime'} || undef)};
  0         0  
2009             }
2010              
2011             #######################################################################
2012             # allmessage(); returns %allmessage;
2013             =pod
2014              
2015             =item *
2016              
2017             C
2018              
2019             %allmessage = $errorlogobject->allmessage();
2020              
2021             Returns a hash containing error messages as keys and the number of
2022             occurrances as values.
2023              
2024             =cut
2025              
2026             sub allmessage {
2027 1     1 0 161 my($this) = shift;
2028 1 50       2 return %{($this->{'allmessage'} || undef)};
  1         26  
2029             }
2030              
2031             #######################################################################
2032             # errorbydate(); returns %errorbydate;
2033             =pod
2034              
2035             =item *
2036              
2037             C
2038              
2039             %errorbydate = $errorlogobject->errorbydate();
2040              
2041             Returns a hash containing date (mm/dd/yyyy) as keys and the number
2042             of error occurrances as values. For the Apache 1.3.x log only.
2043              
2044             =cut
2045              
2046             sub errorbydate {
2047 1     1 0 161 my($this) = shift;
2048 1 50       2 return %{($this->{'errorbydate'} || undef)};
  1         10  
2049             }
2050              
2051             #######################################################################
2052             # errorbytime(); returns %errorbytime;
2053             =pod
2054              
2055             =item *
2056              
2057             C
2058              
2059             %errorbytime = $errorlogobject->errorbytime();
2060              
2061             Returns a hash containing time (00-23) as keys and the number
2062             of error occurrances as values. For the Apache 1.3.x log only.
2063              
2064             =cut
2065              
2066             sub errorbytime {
2067 0     0 0 0 my($this) = shift;
2068 0 0       0 return %{($this->{'errorbytime'} || undef)};
  0         0  
2069             }
2070              
2071             #######################################################################
2072             # errorbydatetime(); returns %errorbydatetime;
2073             =pod
2074              
2075             =item *
2076              
2077             C
2078              
2079             %errorbydatetime = $errorlogobject->errorbydatetime();
2080              
2081             Returns a hash containing date/time (mm/dd/yyyy-hh) as keys and the
2082             number of error occurrances as values. For the Apache 1.3.x log only.
2083              
2084             =cut
2085              
2086             sub errorbydatetime {
2087 0     0 0 0 my($this) = shift;
2088 0 0       0 return %{($this->{'errorbydatetime'} || undef)};
  0         0  
2089             }
2090              
2091             #######################################################################
2092             # errormessage(); returns %errormessage;
2093             =pod
2094              
2095             =item *
2096              
2097             C
2098              
2099             %errormessage = $errorlogobject->errormessage();
2100              
2101             Returns a hash containing error messages as keys and the number of
2102             occurrances as values. For the Apache 1.3.x log only.
2103              
2104             =cut
2105              
2106             sub errormessage {
2107 0     0 0 0 my($this) = shift;
2108 0 0       0 return %{($this->{'errormessage'} || undef)};
  0         0  
2109             }
2110              
2111             #######################################################################
2112             # noticebydate(); returns %noticebydate;
2113             =pod
2114              
2115             =item *
2116              
2117             C
2118              
2119             %noticebydate = $errorlogobject->noticebydate();
2120              
2121             Returns a hash containing date (mm/dd/yyyy) as keys and the number
2122             of error occurrances as values. For the Apache 1.3.x log only.
2123              
2124             =cut
2125              
2126             sub noticebydate {
2127 1     1 0 147 my($this) = shift;
2128 1 50       3 return %{($this->{'noticebydate'} || undef)};
  1         9  
2129             }
2130              
2131             #######################################################################
2132             # noticebytime(); returns %noticebytime;
2133             =pod
2134              
2135             =item *
2136              
2137             C
2138              
2139             %noticebytime = $errorlogobject->noticebytime();
2140              
2141             Returns a hash containing time (00-23) as keys and the number
2142             of error occurrances as values. For the Apache 1.3.x log only.
2143              
2144             =cut
2145              
2146             sub noticebytime {
2147 0     0 0 0 my($this) = shift;
2148 0 0       0 return %{($this->{'noticebytime'} || undef)};
  0         0  
2149             }
2150              
2151             #######################################################################
2152             # noticebydatetime(); returns %noticebydatetime;
2153             =pod
2154              
2155             =item *
2156              
2157             C
2158              
2159             %noticebydatetime = $errorlogobject->noticebydatetime();
2160              
2161             Returns a hash containing date/time (mm/dd/yyyy-hh) as keys and the
2162             number of error occurrances as values. For the Apache 1.3.x log only.
2163              
2164             =cut
2165              
2166             sub noticebydatetime {
2167 0     0 0 0 my($this) = shift;
2168 0 0       0 return %{($this->{'noticebydatetime'} || undef)};
  0         0  
2169             }
2170              
2171             #######################################################################
2172             # noticemessage(); returns %noticemessage;
2173             =pod
2174              
2175             =item *
2176              
2177             C
2178              
2179             %noticemessage = $errorlogobject->noticemessage();
2180              
2181             Returns a hash containing notice messages as keys and the number of
2182             occurrances as values. For the Apache 1.3.x log only.
2183              
2184             =cut
2185              
2186             sub noticemessage {
2187 0     0 0 0 my($this) = shift;
2188 0 0       0 return %{($this->{'noticemessage'} || undef)};
  0         0  
2189             }
2190              
2191             #######################################################################
2192             # warnbydate(); returns %warnbydate;
2193             =pod
2194              
2195             =item *
2196              
2197             C
2198              
2199             %warnbydate = $errorlogobject->warnbydate();
2200              
2201             Returns a hash containing date (mm/dd/yyyy) as keys and the number
2202             of error occurrances as values. For the Apache 1.3.x only.
2203              
2204             =cut
2205              
2206             sub warnbydate {
2207 1     1 0 155 my($this) = shift;
2208 1 50       2 return %{($this->{'warnbydate'} || undef)};
  1         10  
2209             }
2210              
2211             #######################################################################
2212             # warnbytime(); returns %warnbytime;
2213             =pod
2214              
2215             =item *
2216              
2217             C
2218              
2219             %warnbytime = $errorlogobject->warnbytime();
2220              
2221             Returns a hash containing time (00-23) as keys and the number
2222             of error occurrances as values. For the Apache 1.3.x only.
2223              
2224             =cut
2225              
2226             sub warnbytime {
2227 0     0 0 0 my($this) = shift;
2228 0 0       0 return %{($this->{'warnbytime'} || undef)};
  0         0  
2229             }
2230              
2231             #######################################################################
2232             # warnbydatetime(); returns %warnbydatetime;
2233             =pod
2234              
2235             =item *
2236              
2237             C
2238              
2239             %warnbydatetime = $errorlogobject->warnbydatetime();
2240              
2241             Returns a hash containing date/time (mm/dd/yyyy-hh) as keys and the
2242             number of error occurrances as values. For the Apache 1.3.x only.
2243              
2244             =cut
2245              
2246             sub warnbydatetime {
2247 0     0 0 0 my($this) = shift;
2248 0 0       0 return %{($this->{'warnbydatetime'} || undef)};
  0         0  
2249             }
2250              
2251             #######################################################################
2252             # warnmessage(); returns %warnmessage;
2253             =pod
2254              
2255             =item *
2256              
2257             C
2258              
2259             %warnmessage = $errorlogobject->warnmessage();
2260              
2261             Returns a hash containing warn messages as keys and the number of
2262             occurrances as values. For the Apache 1.3.x only.
2263              
2264             =back
2265              
2266             =cut
2267              
2268             sub warnmessage {
2269 0     0 0 0 my($this) = shift;
2270 0 0       0 return %{($this->{'warnmessage'} || undef)};
  0         0  
2271             }
2272              
2273             #######################################################################
2274             # REFERERLOG METHODS
2275             =pod
2276              
2277             =head2 RefererLog/CustomLog Methods
2278              
2279             The following methods are available for the F object
2280             (created by C method), as well as the F
2281             object that logs C<%{Referer}i> to the corresponding F.
2282              
2283             =over 4
2284              
2285             =cut
2286              
2287             ######################################################################
2288             # referer(); returns %referer
2289             =pod
2290              
2291             =item *
2292              
2293             C
2294              
2295             %referer = $logobject->referer();
2296              
2297             Returns a hash containing the name of the web site the visitor comes from
2298             as keys, and the hit count for each key as values.
2299              
2300             Note that the returned data from this method contains B the
2301             site name of the referer, e.g. "www.altavista.digital.com", so if you want to
2302             obtain the full details of the referer as well as the referred files,
2303             use C method described below.
2304              
2305             =cut
2306              
2307             sub referer {
2308 1     1 0 957 my($this) = shift;
2309 1 50       4 return %{($this->{'referer'} || undef)};
  1         13  
2310              
2311             }
2312              
2313             #######################################################################
2314             # refererdetail(); returns %refererdetail
2315             =pod
2316              
2317             =item *
2318              
2319             C
2320              
2321             Returns a hash containing the full URL of the referer as keys, and the
2322             hit count for each key as values.
2323              
2324             The standard log format for the F is -> I>.
2325             With the F object, the object attempts to use the URL first,
2326             and if the URL is not logged, then the relative path, and then the absolute
2327             path to create the key for the returned data I<%referer>. If none of the URL,
2328             relative or absolute paths are logged, the object will use only the referer
2329             URL itself (without refererd files) as the key.
2330              
2331             =back
2332              
2333             =cut
2334              
2335             sub refererdetail {
2336 1     1 0 360 my($this) = shift;
2337 1 50       2 return %{($this->{'refererdetail'} || undef)};
  1         19  
2338             }
2339              
2340             #######################################################################
2341             # AGENTLOG METHODS
2342             =pod
2343              
2344             =head2 AgentLog/CustomLog Methods
2345              
2346             This subsection describes the methods available for the F object
2347             (created by C method), as well as the F
2348             object that logs C<%{User-agent}i> to the corresponding F.
2349              
2350             =over 4
2351              
2352             =cut
2353              
2354             ######################################################################
2355             # uagent(); returns %uagent
2356             =pod
2357              
2358             =item *
2359              
2360             C
2361              
2362             %uagent = $logobject->uagent();
2363              
2364             Returns a hash containing the user agent (the "full name", as you
2365             see in the log file itself) as keys, and the hit count for each
2366             key as values.
2367              
2368             =cut
2369              
2370             sub uagent {
2371 1     1 0 380 my($this) = shift;
2372 1 50       2 return %{($this->{'uagent'} || undef)};
  1         38  
2373             }
2374              
2375             ######################################################################
2376             # uaversion(); returns %uaversion
2377             =pod
2378              
2379             =item *
2380              
2381             C
2382              
2383             %uaversion = $logobject->uaversion();
2384              
2385             Returns a hash containing the most basic and simple information about
2386             the user agent (the first column in the agent log file, e.g.
2387             "C") as keys, and the hit count for each
2388             key as values. Useful to collect the information about the parser engine
2389             and its version, to determine which specs of HTML and/or JavaScript to
2390             deploy, for example.
2391              
2392             =cut
2393              
2394             sub uaversion {
2395 1     1 0 132 my($this) = shift;
2396 1 50       1 return %{($this->{'uaversion'} || undef)};
  1         13  
2397             }
2398              
2399             ######################################################################
2400             # browser(); returns %browser
2401             =pod
2402              
2403             =item *
2404              
2405             C
2406              
2407             %browser = $logobject->browser();
2408              
2409             Returns a hash containing the actual browsers (as logged in the file)
2410             as keys, and the hit count for each key as values.
2411              
2412             For example, Netscape Navigator/Communicator will (still) be reported as
2413             "C>", Microsoft Internet Explorer as "C>",
2414             and so on.
2415              
2416             =cut
2417              
2418             sub browser {
2419 1     1 0 120 my($this) = shift;
2420 1 50       2 return %{($this->{'browser'} || undef)};
  1         14  
2421             }
2422              
2423             ######################################################################
2424             # platform(); returns %platform
2425             =pod
2426              
2427             =item *
2428              
2429             C
2430              
2431             %platform = $logobject->platform();
2432              
2433             Returns a hash containing the names of OS (and possibly its version,
2434             hardware architecture, etc.) as keys, and the hit count for each
2435             key as values.
2436              
2437             For example, Solaris 2.6 on UltraSPARC will be reported as
2438             "C",
2439              
2440             =cut
2441              
2442             sub platform {
2443 1     1 0 120 my($this) = shift;
2444 1 50       1 return %{($this->{'platform'} || undef)};
  1         13  
2445             }
2446              
2447             ######################################################################
2448             # browserbyos(); returns %browserbyos
2449             =pod
2450              
2451             =item *
2452              
2453             C
2454              
2455             %browserbyos = $logobject->browserbyos();
2456              
2457             Returns a hash containing the browser names with OS (in the form,
2458             I) as keys, and the hit count for each key as values.
2459              
2460             =back
2461              
2462             =cut
2463              
2464             sub browserbyos {
2465 1     1 0 119 my($this) = shift;
2466 1 50       2 return %{($this->{'browserbyos'} || undef)};
  1         20  
2467             }
2468              
2469             #######################################################################
2470             # CUSTOMLOG METHODS
2471             =pod
2472              
2473             =head2 CustomLog Methods
2474              
2475             This subsection describes the methods available only for the F
2476             object. See each method for what Apache directive is used for each
2477             returned result.
2478              
2479             =over 4
2480              
2481             =cut
2482              
2483             ######################################################################
2484             # addr(); returns %addr
2485             =pod
2486              
2487             =item *
2488              
2489             C
2490              
2491             %addr = $logobject->addr();
2492              
2493             Returns a hash containing the IP addresses of the B (instead of
2494             the F) visited as keys, and the hit count for each key as
2495             values. (LogFormat C<%a>)
2496              
2497             =cut
2498              
2499             sub addr {
2500 1     1 0 344 my($this) = shift;
2501 1 50       2 return %{($this->{'addr'} || undef)};
  1         11  
2502             }
2503              
2504             ######################################################################
2505             # filename(); returns %filename
2506             =pod
2507              
2508             =item *
2509              
2510             C
2511              
2512             %filename = $logobject->filename();
2513              
2514             Returns a hash containing the absolute paths to the files as keys, and
2515             the hit count for each key as values. (LogFormat C<%f>)
2516              
2517             =cut
2518              
2519             sub filename {
2520 1     1 0 3847 my($this) = shift;
2521 1 50       5 return %{($this->{'filename'} || undef)};
  1         38  
2522             }
2523              
2524             ######################################################################
2525             # hostname(); returns %hostname
2526             =pod
2527              
2528             =item *
2529              
2530             C
2531              
2532             %hostname = $logobject->hostname();
2533              
2534             Returns a hash containing the hostnames of the visitors as keys, and
2535             the hit count for each key as values. (LogFormat C<%v>)
2536              
2537             =cut
2538              
2539             sub hostname {
2540 0     0 0 0 my($this) = shift;
2541 0 0       0 return %{($this->{'hostname'} || undef)};
  0         0  
2542             }
2543              
2544             ######################################################################
2545             # ostatus(); returns %ostatus
2546             =pod
2547              
2548             =item *
2549              
2550             C
2551              
2552             %ostatus = $logobject->ostatus();
2553              
2554             Returns a hash containing HTTP codes and messages (e.g. "404 Not Found")
2555             for the original status (i.e., when the httpd starts processing that
2556             request) as keys, and the hit count for each key as values.
2557              
2558             =cut
2559              
2560             sub ostatus {
2561 1     1 0 52 my($this) = shift;
2562 1 50       2 return %{($this->{'ostatus'} || undef)};
  1         13  
2563             }
2564              
2565             ######################################################################
2566             # port(); returns %port
2567             =pod
2568              
2569             =item *
2570              
2571             C
2572              
2573             %port = $logobject->port();
2574              
2575             Returns a hash containing the port used for the transfer as keys, and
2576             the hit count for each key as values (there will probably be the only
2577             one key-value pair value for each server). (LogFormat C<%p>)
2578              
2579             =cut
2580              
2581             sub port {
2582 0     0 0 0 my($this) = shift;
2583 0 0       0 return %{($this->{'port'} || undef)};
  0         0  
2584             }
2585              
2586             ######################################################################
2587             # proc(); returns %proc
2588             =pod
2589              
2590             =item *
2591              
2592             C
2593              
2594             %proc = $logobject->proc();
2595              
2596             Returns a hash containing the process ID of the server used for
2597             each file transfer as keys, and the hit count for each key as values.
2598             (LogFormat C<%P>)
2599              
2600             =cut
2601              
2602             sub proc {
2603 1     1 0 19 my($this) = shift;
2604 1 50       2 return %{($this->{'proc'} || undef)};
  1         15  
2605             }
2606              
2607             ######################################################################
2608             # sec(); returns %sec
2609             =pod
2610              
2611             =item *
2612              
2613             C
2614              
2615             %sec = $logobject->sec();
2616              
2617             Returns a hash containing the file names (either relative paths,
2618             absolute paths, or the URL, depending on your log format)
2619             as keys, and the maximum seconds it takes to finish the process
2620             as values. Thus, note that the values are not accumulated results,
2621             but rather the highest number of seconds it took to process the file.
2622             (LogFormat C<%T>)
2623              
2624             =cut
2625              
2626             sub sec {
2627 1     1 0 17 my($this) = shift;
2628 1 50       3 return %{($this->{'sec'} || undef)};
  1         26  
2629             }
2630              
2631             ######################################################################
2632             # url(); returns %url
2633             =pod
2634              
2635             =item *
2636              
2637             C
2638              
2639             %url = $logobject->url();
2640              
2641             Returns a hash containing the URLs (path relative to the F>
2642             as keys, and the hit count for each key as values. (LogFormat C<%U>)
2643              
2644             =back
2645              
2646             =cut
2647              
2648             sub url {
2649 1     1 0 378 my($this) = shift;
2650 1 50       3 return %{($this->{'url'} || undef)};
  1         25  
2651             }
2652              
2653             #######################################################################
2654             # SPECIAL METHOD
2655             =pod
2656              
2657             =head2 Special Method
2658              
2659             The special method described below, C, can be used with
2660             B of the B to extract the methods available for the
2661             calling object.
2662              
2663             =over 4
2664              
2665             =cut
2666              
2667             #######################################################################
2668             # getMethods(); returns @methods;
2669             =pod
2670              
2671             =item *
2672              
2673             C
2674              
2675             @object_methods = $logobject->getMethods();
2676              
2677             Returns an array containing the names of the available methods for
2678             that log object. Each of the elements in the array is the name of
2679             one of the methods described in this section.
2680              
2681             By using this method, you can write a I simple Apache log parsing
2682             and reporting script, like so:
2683              
2684             #!/usr/local/bin/perl
2685             $|++; # flush buffer
2686             use Apache::ParseLog;
2687             # Construct the Apache::ParseLog object
2688             $base = new Apache::ParseLog("/usr/local/httpd/conf/httpd.conf");
2689             # Get the CustomLog object for "my_custom_log"
2690             $customlog = $base->getCustomLog("my_custom_log");
2691             # Get the available methods for the CustomLog object
2692             @methods = $customlog->getMethods();
2693             # Iterate through the @methods
2694             foreach $method (@methods) {
2695             print "$method log report\n";
2696             # Get the returned value for each method
2697             %{$method} = $customlog->$method();
2698             # Iterate through the returned hash
2699             foreach (sort keys %{$method}) {
2700             print "$_: ${$method}{$_}\n";
2701             }
2702             print "\n";
2703             }
2704             exit;
2705              
2706             =back
2707              
2708             =cut
2709              
2710             sub getMethods {
2711 0     0 0 0 my($this) = shift;
2712 0 0       0 return @{($this->{'methods'} || undef)};
  0         0  
2713             }
2714              
2715             #######################################################################
2716             # MISCELLANEOUS
2717             #######################################################################
2718             =pod
2719              
2720             =head1 MISCELLANEOUS
2721              
2722             This section describes some miscellaneous methods that might be useful.
2723              
2724             =cut
2725              
2726             #######################################################################
2727             # version(); returns $VERSION
2728             =pod
2729              
2730             =over 4
2731              
2732             =item *
2733              
2734             C
2735              
2736             Returns a scalar containing the version of the Apache::ParseLog module.
2737              
2738             =back
2739              
2740             =cut
2741              
2742 1     1 1 51 sub Version { $VERSION }
2743              
2744             #######################################################################
2745             # EXPORTED METHODS
2746             =pod
2747              
2748             =head2 Exported Methods
2749              
2750             This subsection describes B methods provided by the
2751             Apache::ParseLog module. (For the information about exported methods,
2752             see Exporter(3).)
2753              
2754             Note that those exported modules can be used (called) just like
2755             local (main package) subroutines.
2756              
2757             =over 4
2758              
2759             =cut
2760              
2761             #######################################################################
2762             # countryByCode(); returns %COUNTRY_BY_CODE
2763             =pod
2764              
2765             =item *
2766              
2767             C
2768              
2769             %countryByCode = countryByCode();
2770              
2771             Returns a hash containing a hashtable of country-code top-level domain
2772             names as keys and country names as values. Useful for creating a report
2773             on "hits" by countries.
2774              
2775             =cut
2776              
2777             sub countryByCode {
2778 0     0 0 0 return %COUNTRY_BY_CODE;
2779             }
2780              
2781             #######################################################################
2782             # statusByCode(); returns %STATUS_BY_CODE
2783             =pod
2784              
2785             =item *
2786              
2787             C
2788              
2789             %statusByCode = statusByCode();
2790              
2791             Returns a hash containing a hashtable of status code of the Apache HTTPD
2792             server, as defined by RFC2068, as keys and meanings as values.
2793              
2794             =cut
2795              
2796             sub statusByCode {
2797 0     0 0 0 return %STATUS_BY_CODE;
2798             }
2799              
2800             #######################################################################
2801             # sortHashByValue(); returns @sorted
2802             =pod
2803              
2804             =item *
2805              
2806             C
2807              
2808             @sorted_keys = sortHashByValue(%hash);
2809              
2810             Returns an array containing keys of the I<%hash> B sorted
2811             by the values of the I<%hash>, by the descending order.
2812              
2813             Example
2814              
2815             # Get the custom log object
2816             $customlog = $log->getCustomLog("combined");
2817             # Get the log report on "file"
2818             %file = $customlog->file();
2819             # Sort the %file by hit counts, descending order
2820             @sorted_keys = sortHashByValue(%hash);
2821             foreach (@sorted_keys) {
2822             print "$_: $file{$_}\n"; # print :
2823             }
2824              
2825             =back
2826              
2827             =cut
2828              
2829             sub sortHashByValue {
2830 0     0 0 0 my(%hash) = @_;
2831 0         0 return sort { $hash{$b} <=> $hash{$a} } keys %hash;
  0         0  
2832             }
2833              
2834             #######################################################################
2835             # PRIVATE METHODS
2836             #######################################################################
2837              
2838             #######################################################################
2839             # openFile($any_file); returns a filehandle
2840             sub openFile {
2841 15     15 0 54 my($file) = shift;
2842 15         85 my($METHOD) = "Apache::ParseLog::openFile";
2843 15         57 local(*FH);
2844 15 50       1659 open(FH, "<$file") or croak "$METHOD: Cannot open $file. Exiting ";
2845 15         182 return *FH;
2846             }
2847              
2848             #######################################################################
2849             # ADDITIONAL DOCUMENTATION
2850             #######################################################################
2851             =pod
2852              
2853             =head1 EXAMPLES
2854              
2855             The most basic, easiest way to create reports is presented as an
2856             example in the C section above, but the format of the
2857             output is pretty crude and less user-friendly.
2858              
2859             Shown below are some other examples to use Apache::ParseLog.
2860              
2861             =head2 Example 1: Basic Report
2862              
2863             The example code below checks the F and F
2864             generated by the Apache 1.2.x, and prints the reports to STDOUT.
2865             (To run this code, all you have to do is to change the I<$conf>
2866             value.)
2867              
2868             #!/usr/local/bin/perl
2869             $|++;
2870             use Apache::ParseLog;
2871              
2872             $conf = "/usr/local/httpd/conf/httpd.conf";
2873             $base = new Apache::ParseLog($conf);
2874              
2875             print "TransferLog Report\n\n";
2876             $transferlog = $base->getTransferLog();
2877              
2878             %hit = $transferlog->hit();
2879             %hitbydate = $transferlog->hitbydate();
2880             print "Total Hit Counts: ", $hit{'Total'}, "\n";
2881             foreach (sort keys %hitbydate) {
2882             print "$_:\t$hitbydate{$_}\n"; # :
2883             }
2884             $hitaverage = int($hit{'Total'} / scalar(keys %hitbydate));
2885             print "Average Daily Hits: $hitaverage\n\n";
2886              
2887             %byte = $transferlog->byte();
2888             %bytebydate = $transferlog->bytebydate();
2889             print "Total Bytes Transferred: ", $byte{'Total'}, "\n";
2890             foreach (sort keys %bytebydate) {
2891             print "$_:\t$bytebydate{$_}\n"; # :
2892             }
2893             $byteaverage = int($byte{'Total'} / scalar(keys %bytebydate));
2894             print "Average Daily Bytes Transferred: $byteaverage\n\n";
2895              
2896             %visitorbydate = $transferlog->visitorbydate();
2897             %host = $transferlog->host();
2898             print "Total Unique Visitors: ", scalar(keys %host), "\n";
2899             foreach (sort keys %visitorbydate) {
2900             print "$_:\t$visitorbydate{$_}\n"; #
2901             }
2902             $visitoraverage = int(scalar(keys %host) / scalar(keys %visitorbydate));
2903             print "Average Daily Unique Visitors: $visitoraverage\n\n";
2904            
2905             print "ErrorLog Report\n\n";
2906             $errorlog = $base->getErrorLog();
2907              
2908             %count = $errorlog->count();
2909             %allbydate = $errorlog->allbydate();
2910             print "Total Errors: ", $count{'Total'}, "\n";
2911             foreach (sort keys %allbydate) {
2912             print "$_:\t$allbydate{$_}\n"; # :
2913             }
2914             $erroraverage = int($count{'Total'} / scalar(keys %allbydate));
2915             print "Average Daily Errors: $erroraverage\n\n";
2916              
2917             exit;
2918              
2919             =head2 Example 2: Referer Report
2920              
2921             The F (or F with referer logged) contains the
2922             referer for every single file requested. It means that everytime a page
2923             that contains 10 images is requested, 11 lines are added to the
2924             F, one line for the actual referer (where the visitor
2925             comes from), and the other 10 lines for the images with the
2926             I page containing the 10 images as the referer,
2927             which is probably a little too much more than what you want to know.
2928              
2929             The example code below checks the F that contains referer,
2930             (among other things), and reports the names of the referer sites that
2931             are not the local server itself.
2932              
2933             #!/usr/local/bin/perl
2934             $|++;
2935             use Apache::ParseLog;
2936              
2937             $conf = "/usr/local/httpd/conf/httpd.conf";
2938             $base = new Apache::ParseLog($conf);
2939              
2940             $localserver = $base->servername();
2941              
2942             $log = $base->getCustomLog("combined");
2943             %referer = $log->referer();
2944             @sortedkeys = sortHashByValue(%referer);
2945              
2946             print "External Referers Report\n";
2947             foreach (@sortedkeys) {
2948             print "$_:\t$referer{$_}\n" unless m/$localserver/i or m/^\-/;
2949             }
2950              
2951             exit;
2952              
2953             =head2 Example 3: Access-Controlled User Report
2954              
2955             Let's suppose that you have a directory tree on your site that is
2956             access-controlled by F<.htaccess> or the like, and you want to check
2957             how frequently the section is used by the users.
2958              
2959             #!/usr/local/bin/perl
2960             $|++;
2961             use Apache::ParseLog;
2962              
2963             $conf = "/usr/local/httpd/conf/httpd.conf";
2964             $base = new Apache::ParseLog($conf);
2965              
2966             $log = $base->getCustomLog("common");
2967             %user = $log->user();
2968              
2969             print "Users Report\n";
2970             foreach (sort keys %user) {
2971             print "$_:\t$user{$_}\n" unless m/^-$/;
2972             }
2973              
2974             exit;
2975              
2976             =head1 SEE ALSO
2977              
2978             perl(1), perlop(1), perlre(1), Exporter(3)
2979              
2980             =head1 BUGS
2981              
2982             The reports on lesser-known browsers returned from the F methods
2983             are not always informative.
2984              
2985             The data returned from the C method for F may
2986             be irrelvant if the referred files are not accessed via HTTP (i.e.,
2987             the referer does not start with "http://" string).
2988              
2989             If the base object is created with the I<$virtualhost> specified,
2990             unless the F and F are specified within
2991             the ... , those values specified
2992             in the global section of the I are not shared with
2993             the I<$virtualhost>.
2994              
2995             =head1 TO DO
2996              
2997             Increase the performance (speed).
2998              
2999             =head1 VERSION
3000              
3001             Apache::ParseLog 1.01 (10/01/1998).
3002              
3003             =head1 AUTHOR
3004              
3005             Apache::ParseLog was written and is maintained by Akira Hangai
3006             (akira@discover-net.net)
3007              
3008             For the bug reports, comments, suggestions, etc., please email me.
3009              
3010             =head1 COPYRIGHT
3011              
3012             Copyright 1998, Akira Hangai. All rights reserved.
3013              
3014             This program is free software; You can redistribute it and/or modify
3015             it under the same terms as Perl itself.
3016              
3017             =head1 DISCLAIMER
3018              
3019             This package is distributed in the hope that it will be useful for
3020             many web administrators/webmasters who are too busy to write their own
3021             programs to analyze the Apache log files. However, this package is
3022             so distributed WITHOUT ANY WARRANTY in that any use of the data
3023             generated by this package must be used at the user's own discretion,
3024             and the author shall not be held accountable for any results
3025             from the use of this package.
3026              
3027             =cut
3028              
3029             #######################################################################
3030             # DATA
3031             #######################################################################
3032             __DATA__