The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Apache2::ModLogConfig - a Perl interface to mod_log_config

SYNOPSIS

Call a Perl handler from a CustomLog format specification:

 <Perl>
   use Apache2::ModLogConfig ();

   sub My::Format {
     my ($r)=@_;

     return $a_string;
   }
 </Perl>

 CustomLog LOGFILE "... %{My::Format}^..."

Use a Perl handler as logfile:

 PerlModule Apache2::ModLogConfig
 PerlModule My::LogReceiver

 CustomLog "@perl: My::LogReceiver" "format spec"

Print to a logfile:

 use Apache2::ModLogConfig ();

 sub handler {
   my ($r)=@_;
   ...
   my $log=$r->server->custom_log_by_name('logs/access_log');
   my $success=$log->print($r, qw/тут был вася/, "\n");
   ...
 }

DESCRIPTION

The reason to start this module was to monitor the number of incoming and outgoing bytes for each request. mod_log_config in combination with mod_logio can log these numbers. But in Perl they are really hard to get.

mod_logio uses a network-level input filter as byte counter. The outgoing bytes are counted by the core output filter and reported back to mod_logio if loaded.

Now, with the help of this module you can do 3 things:

  • call a Perl handler from a CustomLog format specification

  • use a Perl handler in place of a logfile

  • write out-of-bound messages to logfiles managed by mod_log_config

For this to work, the module must be loaded before the PerlOpenLogsHandler phase. Calling a Perl handler from a format specification requires an early start of the interpreter and the module must be loaded at that stage. That means you need either a <Perl>...</Perl> section in your httpd.conf or the module must be loaded by PerlLoadModule.

Note, while developing this module I have found a bug in httpd that can lead to segfaults. It is present at least up to httpd 2.2.17. It occurs if mod_log_config is statically compiled into httpd and BufferedLogs are used. In this case avoid changing the BufferedLogs setting while restarting httpd via SIGHUP or SIGUSR1.

See https://issues.apache.org/bugzilla/show_bug.cgi?id=50861

Call a Perl handler from a CustomLog format specification

To be used this way Apache2::ModLogConfig registers the ^ format with mod_log_config.

^ was chosen because it resembles the ^ in a number of Perl variables like $^V for example.

Now, a format specifier can receive an argument. The argument is given in braces between the % sign and the specifier. The ^ specifier's argument specifies the Perl handler to call. A fully qualified name is expected.

Example:

 LogFormat "%{My::Handler::function}^" perllog

The handler is called with an Apache2::RequestRec object as the only parameter. In a chain of internal redirects this is by default the final request. It can be modified according to the mod_log_config documentation:

 LogFormat "%<{My::Handler::function}^" perllog

This way the initial request is passed to the handler.

Other modifiers are also applicable as described by mod_log_config.

Use a Perl handler in place of a logfile

Now Perl handler works as log drain. That means it will receive a log file.

 CustomLog "@perl: My::LogReceiver" FORMATSPEC

The prefix @perl: is used to distinguish between a normal file name or pipe specification and the Perl handler.

The actual handler name is resolved the usual modperl way. That means if there is no function named My::LogReceiver, My::LogReceiver::handler is looked up. Auto-loading should work as well (although untested). Further, an anonymous function can be specified as:

 CustomLog "@perl: sub { my ($r, @strings)=@_; ... }" FORMATSPEC

The handler is called with the final request of a chain of internal redirects as the first parameters. The other parameters are all strings where each one corresponds to either a the result of a format specifier or a constant string.

Assuming the following format specification

 "input bytes=%I, output bytes=%O"

the handler is called with 6 parameters:

  • the request object

  • the string input bytes=

  • a number according to %I

  • the string , output bytes=

  • a number according to %O

  • and a trailing \n to close the line

Note, a possible PerlLogHandler runs before the mod_log_config handler. So, it's not possible to record a few values here and use them in a PerlLogHandler. A PerlCleanupHandler or a request pool cleanup handler however should be fine.

My original problem now can be solved as:

 package My::IO;

 sub handler {
   my ($r, $in, $out)=@_;
   $r->notes->{InBytes}=$in;
   $r->notes->{OutBytes}=$out;
 }

 sub cleanup {
   my ($r)=@_;
   my ($in, $out)=@{$r->notes}{qw/InBytes OutBytes/};
   ...
 }

in httpd.conf:

 CustomLog "@perl: My::IO" "%I%O"
 PerlCleanupHandler My::IO::cleanup

Writing to a CustomLog logfile and introspection

Have you ever wanted to write to the access_log directly? I haven't. But now it's feasible and perhaps someone finds a weird usage case.

Apache2::ModLogConfig implements the following methods.

@names=$s->custom_logs

Assuming $s is a Apache2::ServerRec object this method returns the logfile names defined for this VHost. The elements of @names are literally the strings specified as first parameter to CustomLog.

$log=$s->custom_log_by_name($name)

Assuming $s is a Apache2::ServerRec object this method returns an Apache2::ModLogConfig object for the given name.

$status=$log->print($r, @strings)

Assuming $log is an Apache2::ModLogConfig object and $r is an Apache2::RequestRec this method prints the strings in @strings to the file. No escaping is done.

$status is an APR status code (APR::Const::SUCCESS if all is well).

EXPORT

None.

SEE ALSO

modperl, mod_log_config, apache httpd

AUTHOR

Torsten Förtsch, <torsten.foertsch@gmx.net>

COPYRIGHT AND LICENSE

Copyright (C) 2011 by Torsten Förtsch

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.12.3 or, at your option, any later version of Perl 5 you may have available.