Working Apache and Rsyslog configuration
From rsyslog wiki
[edit] Working Apache and Rsyslog configuration
Post by hkspvt on Tue Jul 08, 2008 9:46 pm
This is just a quick howto for anyone who might want to configure Apache to log to rsyslog. There are other ways to do it (set rsyslog to read in from a file), but this is my preferred method.
Background Apache maintains its own error and access logs. These are fine for some installations, but lack a lot as the complexity/criticality of an environment increases.
How to
First step is to decide what facility you'll be logging to. I decided to log access to local6 and errors to local7 for a few reasons:
- I want to keep access and error logs separate
- I want to leave room for debugging Apache (ie, setting the loglevel in httpd.conf to debug) without mixing the two
- Apache's interaction with syslog isn't particularly well documented
Apache's error logs are very easy to point at syslog with the ErrorLog directive:
ErrorLog syslog:local7
Because the Apache error log uses syslog-standard severity ratings, you can use normal syslog configurations to split syslog output into different files based on severity. For example, if you wanted to log only critical errors to a particular file, add the line in your /etc/rsyslog.conf file:
local1.crit /var/log/apache.crit
This still causes the logging of entries of level crit and higher to the file /var/log/apache.crit.
The access logs are a bit trickier. They don't have a built-in syslog function, but do accept pipes. A quick perl script based off of O'Reilly's article and installed in /usr/local/sbin/apache_syslog does the trick:
#!/usr/bin/perl
use Sys::Syslog qw (:DEFAULT setlogsock);
setlogsock('unix');
# open our log socket
openlog('httpd', 'pid', 'local6');
# log all our input
while (<STDIN>) {
syslog('info', $_);
}
# close the log socket
closelog;
Now you can point your access logs at it with the CustomLog directive in httpd.conf (combined refers to the format - use common if you're unsure): CustomLog |/usr/local/sbin/apache_syslog combined
A C version of the above, which seems to run much faster and with less resource requirements:
#include <stdio.h>
#define SYSLOG_NAMES
#include <syslog.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char *argv[])
{
if (2 != argc)
{
fprintf(stderr, "Usage: stdin-syslogd priority\n");
exit (1);
}
const char *priority_name = argv[1];
int priority = -1;
int i;
for (i = 0; prioritynames[i].c_name; ++i)
{
if (! strcmp(prioritynames[i].c_name, priority_name))
{
priority = prioritynames[i].c_val;
break;
}
}
if (priority < 0)
{
fprintf(stderr, "stdin-syslogd: priority \"%s\" not recognized",
priority_name);
exit (1);
}
openlog("httpd", LOG_PID|LOG_NDELAY, LOG_LOCAL6);
char buffer[8192];
while (NULL != fgets(buffer, sizeof(buffer), stdin))
{
syslog(priority, "%s", buffer);
}
return 0;
}
The above C version is not geared for unicode. I'm not sure but maybe it should be changed to use fgetws and friends.
Now for rsyslog.conf. It's possible that other applications are logging under the local6 and local7 facilities, so we want to log based on both facility and program name. Moreover, having these logs included in multiple places would not be good, so we'll just dump them after we've pulled them out.
==Code: Select all== if $syslogfacility-text == 'local6' and $programname == 'httpd' then /var/log/httpd-access.log if $syslogfacility-text == 'local6' and $programname == 'httpd' then ~ if $syslogfacility-text == 'local7' and $programname == 'httpd' then /var/log/httpd-error.log if $syslogfacility-text == 'local7' and $programname == 'httpd' then ~
Restart rsyslog, then restart Apache, and that's it.
Hopefully that's a help to someone. -HKS

