While Apache's access logs offer extensive customization through the LogFormat
directive, error logs historically had limited formatting options. The standard error log format includes timestamp, log level, and error message, but lacks built-in support for adding virtual host identifiers.
In multi-host environments, error logs without vhost context become difficult to parse. Consider this standard error entry:
[Wed Jul 19 10:28:32 2023] [error] [client 192.168.1.5] File does not exist: /var/www/html/missing.html
You can't tell which virtual host generated this error, making troubleshooting inefficient.
Here are two practical approaches to achieve custom error logging with vhost identification:
1. ErrorLog Directive with Pipe
Apache allows piping logs to external programs. Create a wrapper script that prepends vhost names:
ErrorLog "|/usr/local/bin/vhost-logger -v myvhost.example.com"
Sample wrapper script (vhost-logger
):
#!/bin/sh
while read line; do
echo "[$(date +'%Y-%m-%d %H:%M:%S')] [$1] $line" >> /var/log/apache2/errors.log
done
2. CustomLog with Error-level Messages
Leverage Apache's LogLevel
with CustomLog
:
LogLevel warn
CustomLog "|/path/to/processor" "%v %t [%l] %M" env=error-note
In your virtual host configuration:
SetEnvIf Request_URI ".*" error-note
When implementing custom error logging:
- Ensure your logging script handles high traffic volumes
- Consider asynchronous processing for the pipe output
- Monitor system resources during peak loads
While this question specifically addresses Apache 2.2, note that Apache 2.4+ introduced ErrorLogFormat
:
ErrorLogFormat "[%{u}t] [%-m:%l] [pid %P:tid %T] %7F: %E: [client\ %a] %M% ,\ referer\ %{Referer}i"
This makes vhost-aware error logging significantly easier in modern versions.
Here's a complete virtual host configuration with custom error processing:
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/example
ErrorLog "|/usr/local/bin/vhost-logger example.com"
CustomLog "|/usr/local/bin/vhost-logger example.com" combined
LogLevel warn
</VirtualHost>
The accompanying processor script (vhost-logger
) might look like:
#!/usr/bin/perl
use strict;
use warnings;
my $vhost = shift @ARGV;
while (my $line = <STDIN>) {
open(my $fh, '>>', "/var/log/apache2/${vhost}_error.log") or die $!;
print $fh "[".localtime()."] $line";
close $fh;
}
While Apache's access logs famously support the LogFormat
directive for complete customization, error logs have traditionally been more rigid in their formatting. However, with some creative configuration, we can achieve similar functionality for error logs.
The standard error log format in Apache 2.2 doesn't include virtual host information by default, making it difficult to:
- Distinguish between errors from different vhosts in shared environments
- Pipe logs to custom processing scripts with host context
- Maintain organized error tracking across multiple sites
Here's a technique to prepend vhost names to error logs:
# In your virtual host configuration
<VirtualHost *:80>
ServerName example.com
ErrorLog "|/usr/bin/logger -t example.com_error"
CustomLog "|/usr/bin/logger -t example.com_access" combined
</VirtualHost>
For more sophisticated processing, you can create a wrapper script:
#!/usr/bin/perl
use strict;
use warnings;
while (<STDIN>) {
print "[$ENV{'APACHE_VHOST'}] $_";
}
Configure Apache to use it:
SetEnv APACHE_VHOST example.com
ErrorLog "|/path/to/your/script.pl >> /var/log/apache2/error.log"
For systems using syslog, you can leverage its tagging capabilities:
ErrorLog "syslog:local1"
Then configure syslog to handle the tagging:
local1.* /var/log/apache2/error.log
Remember that piping logs to external programs adds overhead. For high-traffic sites:
- Consider buffering mechanisms
- Implement log rotation at the script level
- Monitor the additional process's resource usage
Here's a complete vhost configuration demonstrating the technique:
<VirtualHost *:80>
ServerName client1.example.com
DocumentRoot /var/www/client1
SetEnv VHOST_ID client1
ErrorLog "|/usr/local/bin/vhost-logger --type=error --vhost=client1"
CustomLog "|/usr/local/bin/vhost-logger --type=access --vhost=client1" combined
</VirtualHost>