Linux System Log Rotation

/etc/logrotate.d

--------------------------------------------------------------------------------

Setting up and verifying system logging: syslog and klog; /etc/syslog.conf;
remote logging; monitoring logs using swatch; managing logs using log rotate. 

It is possible to force log rotation to test new configuration.

{
  dbw comment: invalid entries in logrotate.conf - such as logs for customer 
  web directories since deleted, can cause logrotate to fail completely!  You
  _can_ force a log rotation checking your logrotate.conf file for validity.
  syntax: logrotate -f /etc/logrotate.conf

Test without actually rotating and show details: logrotate -vd /etc/logrotate.conf

}

man logrotate

--------------------------------------------------------------------------------
#note: endscript should appear only in the last entry if in logrotate.d
#      and should not appear at all if in logrotate.conf
--------------------------------------------------------------------------------
How logrotate is invoked from cron. 
On one of my RedHat 5.2 systems, `crond' is started from the script 
/etc/rc.d/init.d/crond. The manual `man cron' says that cron 

searches for /etc/crontab and the files in the /etc/cron.d/ directory.

My /etc/crontab file contains the following. 
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

# run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
0  0 1 * * root run-parts /etc/cron.monthly

And the /etc/cron.d directory contains nothing. 
So clearly, any logrotate commands are being run out of one or more of the 
/etc/cron.* files. The manual `man 5 crontab' indicates that the above 
commands mean that the program `run-parts' will be run as user `root' for 
each of the scripts. 

The command `run-parts' turns out to be the script /usr/bin/run-parts, which 
is very short, as follows. 

#!/bin/bash

# run-parts - concept taken from Debian

# keep going when something fails
set +e

if [ $# -lt 1 ]; then
        echo "Usage: run-parts <dir>"
        exit 1
fi

if [ ! -d $1 ]; then
        echo "Not a directory: $1"
        exit 1
fi

for i in $1/* ; do
        [ -d $i ] && continue
        if [ -x $i ]; then
                $i
        fi
done

exit 0

In essence, this just runs all of the scripts in the specified directory. 
E.g. each hour, the executable plain files in /etc/cron.hourly are run. 
It turns out that the `logrotate' program is invoked from /etc/cron.daily. 
This is the contents of the file /etc/cron.daily/logrotate. 

#!/bin/sh

/usr/sbin/logrotate /etc/logrotate.conf

This means that the only file that `logrotate' gets its instructions from 
directly is /etc/logrotate.conf, which contains the following lines. 
# see "man logrotate" for details
# rotate log files weekly
weekly

# keep 8 weeks worth of backlogs
rotate 8

# send errors to root
errors root

# create new (empty) log files after rotating old ones
create

# uncomment this if you want your log files compressed
#compress

# RPM packages drop log rotation information into this directory
include /etc/logrotate.d

# no packages own lastlog or wtmp -- we'll rotate them here
/var/log/wtmp {
    monthly
    rotate 1
}

# system-specific logs may be configured here

This is all explained in the manual `man logrotate'.  


Operation of logrotate. 
The directory /etc/logrotate.d contains the following files. 

-rw-r--r--   1 root     root          354 Oct 13  1998 apache
-rw-r--r--   1 root     root          108 Aug 28  1999 cron
-rw-r--r--   1 root     root          188 Oct 14  1998 linuxconf
-rw-r--r--   1 root     root          156 Oct 13  1998 mgetty
-rw-r--r--   1 root     root          327 Aug 12  1998 syslog
-rw-r--r--   1 root     root          457 Sep 10  1998 uucp

The file /etc/logrotate.d/apache is the one I'm interested in for this 
exercise. This file contains the following. 

/var/log/httpd/access_log {
    postrotate
        /usr/bin/killall -HUP httpd
    endscript
}

/var/log/httpd/agent_log {
    postrotate
        /usr/bin/killall -HUP httpd
    endscript
}

/var/log/httpd/error_log {
    postrotate
        /usr/bin/killall -HUP httpd
    endscript
}

/var/log/httpd/referer_log {
    postrotate
        /usr/bin/killall -HUP httpd
    endscript
}

When I installed the latest version of Apache to get the PHP3 and 
PostgreSQL to work (around 20 March 2000) on my web server machine, 
I installed Apache so that the log files were in /home2/apache/logs 
instead of /var/log/httpd. 

Therefore what I need to do now is to modify the 
/etc/logrotate.d/apache file so that the files referred to are all 
in the directory /home2/apache/logs instead. My new 
/etc/logrotate.d/apache script is as follows, and I saved the old 
one in directory /etc/logrotate.d/old1. 

# The new improved logrotate script for apache on fox.

/home2/apache/logs/*-access_log {
    rotate 9
    monthly
    errors akenning@fox.topology.org
    create
    ifempty
    olddir /home2/apache/logs/oldlogs
    postrotate
        /usr/bin/killall -HUP httpd
    endscript
    }

/home2/apache/logs/*-combref_log {
    rotate 9
    monthly
    errors akenning@fox.topology.org
    create
    ifempty
    olddir /home2/apache/logs/oldlogs
    postrotate
        /usr/bin/killall -HUP httpd
    endscript
    }

/home2/apache/logs/*-error_log {
    rotate 9
    monthly
    errors akenning@fox.topology.org
    create
    ifempty
    olddir /home2/apache/logs/oldlogs
    postrotate
        /usr/bin/killall -HUP httpd
    endscript
    }

--------------------------------------------------------------------------------

Now on Sunday 30 September 2001, it's time to get `logrotate' going on my new 
SuSE 7.1 web server `dog'. The problem is that SuSE 7.1 does not come with 
logrotate software on it. So I had to go and look for it. The link at redhat
was 
wrong, but by looking around a bit, I finally found it at 
ftp://ftp.redhat.com/pub/redhat/linux/code/logrotate/ 
I downloaded this file: logrotate-3.3.tar.gz. This can be compiled very simply 
with `make' and `make install'. There's a manual logrotate.8 with it too. The 
binary is installed as /usr/sbin/logrotate. So now all I have to do is write a 
configuration file for the logrotate program and then write a cron script for
it. 
(Note that since my main initial consideration is to rotate the httpd logs for 
the beginning of October 2001, I could just use the Apache tool for this
purpose, 
which is /usr/local/apache/bin/rotatelogs on my system. However, I can't 
understand the documentation for this. So I'm playing safe and using the more 
flexible redhat `logrotate' tool instead.) 

On my SuSE 7.1 machine `dog', the manual says that after reading the per-user 
crontab files in /var/spool/cron/tabs on start-up, the cron process reads the 
file /etc/crontab. On my machine as configured, I find the following. 

root@dog# more /etc/crontab
SHELL=/bin/sh
PATH=/usr/bin:/usr/sbin:/sbin:/bin:/usr/lib/news/bin
MAILTO=root

#-* * * * *    root  test -x /usr/sbin/atrun && /usr/sbin/atrun
0 21 * * *     root  test -x /usr/sbin/faxqclean && /usr/sbin/faxqclean
5 22 * * *     root  test -x /usr/sbin/texpire && /usr/sbin/texpire
25 23 * * *    root  test -e /usr/sbin/faxcron && sh /usr/sbin/faxcron | mail
FaxMaster

#
# check scripts in cron.hourly, cron.daily, cron.weekly, and cron.monthly
#
-*/15 * * * *   root  test -x /usr/lib/cron/run-crons &&
/usr/lib/cron/run-crons
59 *  * * *     root  rm -f /var/spool/cron/lastrun/cron.hourly
14 0  * * *     root  rm -f /var/spool/cron/lastrun/cron.daily
29 0  * * 6     root  rm -f /var/spool/cron/lastrun/cron.weekly
44 0  1 * *     root  rm -f /var/spool/cron/lastrun/cron.monthly

There's nothing here to help me with initiating my daily script. (By the way, 
the fax commands are a bit worrying. I'll get rid of those when I understand 
exactly what they do. They obviously produce many meaningless message which 
root receives every day!) 

So my next step is to look at the files in /etc/cron.d, because the cron
manual 
says that all scripts in this directory are read next. On my machine the only 
file in /etc/cron.d is a script `seccheck', which produces copious useless 
messages to root every day and week. (I'll see if I can get rid of that some 
day too!) 

The directory /etc/cron.daily contains a script `aaa_base_rotate_logs' which 
contains a complex set of rotation rules, but how are the scripts in this 
directory invoked? Hmmm... Maybe they're invoked from that 
`/usr/lib/cron/run-crons' script. Yes!! That's where it's invoked from. Yet 
another big, incomprehensible script. The core of that script is the following 
Bourne-shell loop. 

SPOOL=/var/spool/cron/lastrun
for CRONDIR in /etc/cron.{hourly,daily,weekly,monthly} ; do
    test -d $CRONDIR || continue
    BASE=${CRONDIR##*/}
    test -e $SPOOL/$BASE && {
        case $BASE in
          cron.hourly)  TIME="-cmin  +60 -or -cmin  60" ;;
          cron.daily)   TIME="-ctime +1  -or -ctime 1"  ;;
          cron.weekly)  TIME="-ctime +7  -or -ctime 7"  ;;
          cron.monthly) TIME="-ctime +`date -u +%d`"    ;;
        esac
        eval find $SPOOL/$BASE $TIME | xargs -r rm -f
    }
    if test ! -e $SPOOL/$BASE ; then
        touch $SPOOL/$BASE

        # keep going when something fails
        set +e
        for SCRIPT in $CRONDIR/*[^~,] ; do
            test -d $SCRIPT && continue
            test -x $SCRIPT || continue
           case "$SCRIPT" in
               *.rpm*)         continue ;;
               *.swap)         continue ;;
               *.bak)          continue ;;
               *.orig)         continue ;;
               \#*)            continue ;;
           esac
           /sbin/checkproc $SCRIPT && continue
           nice -15 $SCRIPT
        done
    fi
done

Now what does this mean? 
The command `BASE=${CRONDIR##*/}' means that BASE is set to the `longest 
substring of $CRONDIR which matches pattern "*/"', according to my Bash 
reference card. This just means that the leading path components are removed. 
(This is done more simply in C-shell!) In the case of the daily cron job, if 
there is a file /var/spool/cron/lastrun/cron.daily (which is true), then the 
following command is run. 
eval find /var/spool/cron/lastrun/cron.daily -ctime +1 -or -ctime 1 | xargs -r
rm -f

The `xargs' command (which I have never seen before) builds and executes a 
command line from standard input. Wierd! The `xargs' manual says this. 

If  the  standard  input  does not contain any non-blanks,
do not run the command.  Normally, the command is run once
even if there is no input.

So in this case, the command `rm -f' is executed for each of the files with 
modification times within 24 hours of the current time. I don't really 
understand this. 

It looks like the file removal commands in the file /etc/crontab are designed 
to synchronise the operation of the quarter-hour operations. The commands are 
only executed if the files in /var/spool/cron/lastrun have been removed. What 
a convoluted way of achieving a simple objective!! 

Next any file in the directory /etc/cron.daily which do not end in the 
characters `~' or `,' (presumed to be edited files) are executed if they are 
executable and do not have the endings .rpm, .swap, .bak or .orig as follows. 

           /sbin/checkproc $SCRIPT && continue
           nice -15 $SCRIPT

The loop continues is the process is already running. Otherwise it is run with 
nice level 15. 

What this all means finally is that any script in the directory
/etc/cron.daily 
will be run at 00:00 on each day. More to the point, the /etc/cron.monthly 
scripts are run at 00:00 at the beginning of each month. It all looks a bit 
dodgy because the `date' test is `date -u', which gives the current UTC day. 
But this should work, although the motivation for the `-u' is not quite clear. 

All I have to do now is write a script and put it in /etc/cron.monthly. No
problem! 

--------------------------------------------------------------------------------
sample methods:

# system-specific logs may be configured here 
 ## rotate apache logs weekly, keeping 8 rotations
 /www/apache/var/logs/*log {
     rotate 8
     postrotate
       kill -HUP `cat /www/apache/var/logs/httpd.pid`
     endscript
 }
 ## rotate rembo logs weekly, keeping 4 rotations
 /opt/rembo/logs/*.log {
     rotate 4
     postrotate
       /etc/rc.d/init.d/rembo stop
       /etc/rc.d/init.d/rembo start
     endscript
 }

--------------------------------------------------------------------------------
the roach method (for virtual hosting):

I have many virtual hosts.  I feared that apache would be start/stop
frequently,
once per virtual host, during the rotation process.  Therefore, I decided to
use
the 'copytruncate' option.  With this option the apache web server does not 
require a restart. -roach

/usr/apache/log/*log {
    weekly
    rotate 52
    notifempty
    missingok
    copytruncate
}

/usr/apache/log/dynahost.dbw.org/*log {
    weekly
    rotate 52
    notifempty
    missingok
    copytruncate
}

--------------------------------------------------------------------------------
Configure the new /etc/logrotate.d/apache file
Now Apache logs files residing in the /chroot/var/log/httpd directory instead
of 
/var/log/httpd and for this reason we need to modify the
/etc/logrotate.d/httpd 
file to point to the new chrooted directory. Also, we've compiled Apache with 
mod_ssl, so we'll add one more line to permit the logrotate program to rotate 
the ssl_request_log and ssl_engine_log files. Configure your 
/etc/logrotate.d/apache file to rotate your log files each week automatically. 

Create the apache file, touch /etc/logrotate.d/apache and add:         
/chroot/httpd/var/log/httpd/access_log {
        missingok
        postrotate
        /usr/bin/killall -HUP /chroot/httpd/usr/sbin/httpd
        endscript
        }

        /chroot/httpd/var/log/httpd/error_log {
        missingok
        postrotate
        /usr/bin/killall -HUP /chroot/httpd/usr/sbin/httpd
        endscript
        }

        /chroot/httpd/var/log/httpd/ssl_request_log {
        missingok
        postrotate
        /usr/bin/killall -HUP /chroot/httpd/usr/sbin/httpd
        endscript
        }

        /chroot/httpd/var/log/httpd/ssl_engine_log {
        missingok
        postrotate
        /usr/bin/killall -HUP /chroot/httpd/usr/sbin/httpd
        endscript
        }

--------------------------------------------------------------------------------
Credits and Quasi-bibliography:

The majority of this text is from:
http://www.topology.org/linux/logrotate.html
Reference: Alan Kennington's 

Some information was gathered from:
http://misc.epfl.ch/rembo/logrotate_conf.html
Reference: Unknown

Securing and Optimizing Linux: RedHat Edition -A Hands on Guide 
http://www.tldp.org/LDP/solrhe/Securing-Optimizing-Linux-RH-Edition-v1.3/chap29sec258.html

Anything else was created by:
roach

date: Sun May 12 18:03:33 CDT 2002
--------------------------------------------------------------------------------

Logrotate: error reading top line of /var/lib/logrotate.status

If you get an error saying

/etc/cron.daily/logrotate:

error: error reading top line of /var/lib/logrotate.status

delete /var/lib/logrotate.status, and then run logrotate once with -f flag,
like

 #> logrotate -f /etc/logrorate.d/syslog

This should initialize the status file and the error should not be repeating.



Virtual Host Log Rotation for Apache

Many linux distributions include a utility called logrotate.d which is installed and configured by default. It is configured to rotate the main Apache log file typically weekly or monthly. Yet, Apache configuration for virtual hosts (virtual_host) suggests creating separate logs for each virtual host, and in a directory named for the site. This is typically under the primary Apache log directory. Consider a server where /var/log/apache2/access.log is the primary apache log, but there is a virtual host which a log under /var/log/apache2/www.smokinghotbabes.com/access.log. Now looking in /etc/logrotate.d/httpd the default config is:

/var/log/apache2/*.log {
    missingok
    notifempty
    postrotate 
	/usr/bin/killall -HUP httpd
    endscript
}

This default installed configuration for logrotate.d/httpd will only rotate the primary web site. It will not rotate virtual host sites. This can be amended by adding another part to the log rotation configuration script:

/var/log/apache2/*.log {
    missingok
    notifempty
    postrotate 
	/usr/bin/killall -HUP httpd
    endscript
}
/var/log/apache2/*/*.log {
    missingok
    notifempty
    postrotate 
	/usr/bin/killall -HUP httpd
    endscript
}

configuration testing and some important flags

Verbose

-v tells logrotate to say what it’s doing while it’s doing it. It’s very useful when trying to find out why logrotate doesn’t rotate a log when you want it to.

Debug

-d tells logrotate to go through the motions of rotating logs but not actually rotate them. Good for checking that the config file is formatted properly and that logrotate can find the log files it would rotate. It doesn’t actually run the rotations and it doesn’t test some parts of the process like the postrotate scripts.

Force

-f forces logrotate to rotate all logs, whether or not they would normally need to be rotated at that time.

External Resources

 

Last modified on 26 April 2013, at 19:21