Linux System Log Rotation

From Free Knowledge Base- The DUCK Project: information for everyone
Revision as of 18:18, 25 June 2007 by Admin (Talk | contribs)

Jump to: navigation, search
/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
}

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.