Case 17. Archiving the Old Log

Keywords: Linux shell less

There is log rotate in Linux system. It can cut and archive old logs according to our expectation. It can also compress the cut logs and define the retention time of old logs.

The requirement of this case is to use shell script to implement logrotate-like functions. Specific requirements are as follows:

1) The log path to be processed: / data/logs/1.log

2) Cut logs at 0:0 every day

3) Keep the old log for one week

4) The name of the archived log is: 1.log.1, 1.log.2,..., 1.log.7

5) Assuming that new logs can be automatically generated after archiving


Knowledge Point 1: logrotate

First of all, this case script will not refer to this part of the knowledge points, here is only a brief introduction, the following through a configuration to explain its meaning.

/var/log/messages {    //Log Path
       rotate  5       //Keep 5 archived logs
       weekly          //Cut once a week
       postrotate      //After defining the cutting day, the instructions to be executed
           /usr/bin/killall -HUP syslogd  //Overload the syslogd service, which generates a new / var/log/messages file
       endscript       //This is the end of executing shell commands.
}

  "/var/log/httpd/access.log" /var/log/httpd/error.log  {  //The path of writing multiple logs at the same time
       rotate  5
       mail www@my.org  //Send the archived log to the mailbox
       size  100k       //Cutting begins when the log file reaches 100k
       sharedscripts    //For all logs defined on the first line, the following shell command (/ usr/bin/killall - HUP httpd) runs only once, not once for every log cut.
       postrotate
            /usr/bin/killall -HUP httpd
       endscript     
  }
  
    /var/log/news/* {  //Support * Wired
    monthly    //Cut logs once a month
    rotate  2  //Keep 2 archive logs
    olddir /var/log/news/old  //Save the cut logs under this directory
    missingok  //If the log file is lost, no error is reported.
    postrotate
       kill -HUP 'cat /var/run/inn.pid'
    endscript
    nocompress  //The archived log is uncompressed, and its relative parameter is compress.
    }


Knowledge Point 2: exit, break, and continue in the shell

1)exit

If you use exit in shell scripts, you exit the current script directly, and all subsequent instructions of exit are no longer executed. The example script exit.sh:

#!/bin/bash
for i in `seq 1 5`
do
        echo $i
        if [ $i -eq 3 ]
        then
            exit 1
        fi
        echo $i
done
echo aaaaa

The script is executed as follows:

# sh exit.sh 
1
1
2
2
3

exit can be followed by a number indicating the return value of the script. After executing the script, echo $? Can be executed to print the return value of the script.

# echo $?
1


2)break

In a shell script loop, break can be used to jump out of the loop body. The sample script break.sh:

#!/bin/bash
for i in `seq 1 5`
do
        echo $i
        if [ $i -eq 3 ]
        then
            break
        fi
        echo $i
done
echo aaaaa

The script is executed as follows:

# sh break.sh 
1
1
2
2
3
aaaaa

Explanation: When $i is 3, the break instruction is encountered, and the whole loop is jumped out, thus the echo aaaaa instruction is executed.


3)continue

Similar to break, the function of continue is to end this cycle and continue the next one without ending the whole cycle. The sample script continues.sh:

#!/bin/bash
for i in `seq 1 5`
do
        echo $i
        if [ $i -eq 3 ]
        then
            continue
        fi
        echo $i
done
echo aaaaa

The script is executed as follows:

# sh continue.sh 
1
1
2
2
3
4
4
5
5
aaaaa

Explanation: When $i=3, you encounter a continue instruction, and then end the cycle. That is, the instruction echo $i after continue is no longer executed, and continue the subsequent cycle, i=4.


Reference script for this case

#!/bin/bash
#Log cutting file, cut by day, 1.log changes 1.log.1, 1.log.1 changes 1.log.2,...
#Authors:
#Date:

logdir=/data/logs/

#Define functions, delete if a file exists
function e_df()
{
    if [ -f $1 ]
    then
        rm -f $1
    fi
}

cd $logdir

#From 7 to 2, traverse the cycle in turn
for i in `seq 7 -1 2`
do
    #$i2 is 1 less than $i
    i2=$[$i-1]
    
    #First, determine whether 1.log.7 exists or not, and delete it if it exists.
    e_df  1.log.$i

    #When 1.log.6 exists, then 1.log.6 is renamed 1.log.7, and so on.
    if [ -f  1.log.$i2 ]
    then
        mv  1.log.$i2 1.log.$i
    fi
done

#Because 1.log has no suffix after it, so we can't go to the for loop above, we can only take it out to deal with it separately.
e_df 1.log.1
mv  1.log 1.log.1

##Explanation: After the script is written, it is put into the task plan and executed at 0:0 every day.


Demand expansion

Now the requirement is that the logs are cut by size. For example, when the logs are larger than or equal to 100M, they need to be processed. The processed logs need to be compressed and delayed for one day, i.e. 1.log.1 does not need to be compressed. Others need to be compressed.

#!/bin/bash
#Log cutting and archiving, according to the log size cut (100M), 1.log changed 1.log.1, 1.log.1 changed 1.log.2,...
#Authors:
#Date:

logdir=/data/logs/

#Technology 1.log size
size=`du -sk $logdir/1.log |awk '{print $1}`

#If 1.log is less than 100M, exit the script
if [ $size -lt 10240 ]
then
    exit 0
fi

#Define functions, delete if a file exists
function e_df()
{
    if [ -f $1 ]
    then
        rm -f $1
    fi
}

cd $logdir

#If 1.log.1 exists, first compress it to 1.log.1.gz so that the following for loop does not go wrong
if [ -f 1.log.1 ]
then
    gzip 1.log.1
fi
#Since 1.log.1 has been compressed to 1.log.gz, it is possible to rename 1.log.1 directly.
mv  1.log 1.log.1

#From 7 to 2, reverse cycle
for i in `seq 7 -1 2`
do
    #$i2 is 1 less than $i
    i2=$[$i-1]
    
    #First, we judge whether 1.log.7.gz exists or not, and delete it if it exists.
    e_df  1.log.$i.gz

    #When 1.log.6.gz exists, 1.log.6.gz is renamed 1.log.7.gz, and so on.
    if [ -f  1.log.$i2.gz ]
    then
        mv  1.log.$i2.gz 1.log.$i.gz
    fi
done

##Note: Since we need to cut the log size, it needs to be executed every minute after the script is written.


Posted by psychosquirrel on Sun, 18 Aug 2019 21:20:54 -0700