Apache-DBILogConfig

 view release on metacpan or  search on metacpan

DBILogConfig.pm  view on Meta::CPAN

package Apache::DBILogConfig;

require 5.004;

use strict;

# MODULES

use mod_perl 1.11_01;
use Apache::Constants qw( :common );
use DBI;
use Date::Format;

$Apache::DBILogConfig::VERSION = "0.02";

# List of allowed formats and their values
my %Formats = 
  (
	 'a' => sub {return (shift)->connection->remote_ip}, # Remote IP Address
	 'A' => sub {}, # Local IP-address
	 'b' => sub {return (shift)->bytes_sent || '-'}, # Bytes sent, excluding heaers, in CLF format
	 'B' => sub {return (shift)->bytes_sent}, # Bytes sent, excluding heaers
	 'c' => sub {}, # Connection status when response is completed (X, +, -)
   'e' => sub {return (shift)->subprocess_env(shift)}, # Any environment variable
   'f' => sub {return (shift)->filename}, # Filename
   'h' => sub {return (shift)->get_remote_host}, # Remote host
   'H' => sub {return (shift)->protocol}, # The request protocol
   'i' => sub {return (shift)->header_in(shift)}, # A header in the client request
   'l' => sub {return (shift)->get_remote_logname}, # Remote log name (from identd)
   'm' => sub {return (shift)->method}, # The request method
   'n' => sub {return (shift)->notes(shift)}, # The contents of a note from another module
   'o' => sub {return (shift)->header_out(shift)}, # A header from the reply
   'p' => sub {return (shift)->get_server_port}, # Server port
   'P' => sub {return $$}, # Apache child PID
	 'q' => sub {return $_[0]->args ? '?' . $_[0]->args : ''}, # The query string (prepended with a ?
	                                                             # if the query exists)
   'r' => sub {return (shift)->the_request}, # First line of the request
   's' => sub {return (shift)->status}, # Status
   't' => sub {return time2str $_[1] || "%d/%b/%Y:%X %z", $_[0]->request_time}, # Time: CLF or strftime
   'T' => sub {return time - (shift)->request_time}, # Time taken to serve the request
   'u' => sub {return (shift)->connection->user}, # Remote user from auth
   'U' => sub {return (shift)->uri}, # URL
   'v' => sub {return (shift)->server->server_hostname}, # The canonical ServerName
   'V' => sub {} # The UseCanonicalName server name
  );

# SUBS

sub logger {

  my $r = shift;
  $r = $r->last; # Handle internal redirects
  $r->subprocess_env; # Setup the environment

  # Connect to the database
  my $source = $r->dir_config('DBILogConfig_data_source');
  my $username = $r->dir_config('DBILogConfig_username');
  my $password = $r->dir_config('DBILogConfig_password');
  my $dbh = DBI->connect($source, $username, $password);
  unless ($dbh) { 
    $r->log_error("Apache::DBILogConfig could not connect to $source - $DBI::errstr");
    return DECLINED;
  } # End unless
  $r->warn("DBILogConfig: Connected to $source as $username");

  # Parse the formats ( %[conditions]{param}format=field [...] )
  my @format_list = (); # List of anon hashes {field, format, param, conditions}
	my $format_string = Apache->request->dir_config('DBILogConfig_log_format');
	while ($format_string =~ /%(!)?([^\{[:alpha:]]*)(?:\{([^\}]+)\})?(\w)=(\S+)/g) {
		my ($op, $conditions, $param, $format, $field) = ($1, $2, $3, $4, $5);

		# Or conditions together
    my @conditions = map q($r->status ==  ) . $_, split /,/, $conditions;
    $conditions = join(' or ', @conditions);

    $conditions = qq{!($conditions)} if $op eq '!'; # Negate if necessary
    $conditions ||= 1; # If no conditions we want a guranteed true condition
    $r->warn("DBILogConfig: format=$format, field=$field, param=$param, conditions=$conditions");
    push @format_list, {'field' => $field, 'format' => $format, 'param' => $param, 
												'conditions' => $conditions};
  } # End foreach

  # Create the statement and insert data
  my $table = $r->dir_config('DBILogConfig_table');
  @format_list = grep eval $_->{'conditions'}, @format_list; # Keep only ones whose conditions are true
  my $fields = join ', ', map $_->{'field'}, @format_list; # Create string of fields
  my $values = join ', ', map $dbh->quote($Formats{$_->{'format'}}->($r, $_->{'param'})), @format_list; # Create str of values
  my $statement = qq(INSERT INTO $table ($fields) VALUES ($values));
  $r->warn("DBILogConfig: statement=$statement");
  $dbh->do($statement);

  $dbh->disconnect;

  return OK;

} # End logger

sub handler {shift->post_connection(\&logger)}

1;

__END__

=head1 NAME

Apache::DBILogConfig - Logs access information in a DBI database

=head1 SYNOPSIS

 # In httpd.conf
 PerlLogHandler Apache::DBILogConfig
 PerlSetVar DBILogConfig_data_source DBI:Informix:log_data
 PerlSetVar DBILogConfig_username    informix
 PerlSetVar DBILogConfig_password    informix
 PerlSetVar DBILogConfig_table	     mysite_log
 PerlSetVar DBILogConfig_log_format  "%b=bytes_sent %f=filename %h=remote_host %r=request %s=status"

=head1 DESCRIPTION

This module replicates the functionality of the standard Apache module, mod_log_config,
but logs information in a DBI-compliant database instead of a file. (Some documentation has been
borrowed from the mod_log_config documentation.)

=head1 LIST OF TOKENS

=over 4

=item DBILogConfig_data_source

A DBI data source with a format of "DBI::driver:database"

=item DBILogConfig_username

Username passed to the database driver when connecting

=item DBILogConfig_password

Password passed to the database driver when connecting

=item DBILogConfig_table

Table in the database for logging

=item DBILogConfig_log_format

A string consisting of formats separated by white space that define the data to be logged (see FORMAT STRING below)

=back

=head1 FORMAT STRING

A format string consists of a string with the following syntax:

B<%[conditions][{parameter}]format=field>

=head2 format

Formats specify the type of data to be logged. The following formats are accepted:

=over

=item a Remote IP-address

=item A Local IP-address (not yet supported)

=item B Bytes sent, excluding HTTP headers.

=item b Bytes sent, excluding HTTP headers. In CLF format
        i.e. a '-' rather than a 0 when no bytes are sent.

=item c Connection status when response is completed.
        'X' = connection aborted before the response completed.
        '+' = connection may be kept alive after the response is sent.
        '-' = connection will be closed after the response is sent.
        (not yet supported)

=item e The contents of the environment variable specified by parameter

=item f Filename

=item h Remote host

=item H The request protocol

=item i The contents of the header (specified by parameter) in the request sent to the server.

=item l Remote logname (from identd, if supplied)

=item m The request method

=item n The contents of note (specified by parameter) from another module.

=item o The contents of the header (specified by parameter) in the reply.

=item p The canonical Port of the server serving the request



( run in 1.501 second using v1.01-cache-2.11-cpan-2398b32b56e )