案例十七、歸檔老日誌

Linux系統中有日誌切割的工具logrotate,它可以按照我們的預期按時間或者大小來切割和歸檔老的日誌,它還可以壓縮切割後的日誌,也可以定義老日誌保留的時間。

本案例的需求是用shell腳本來實現類似logrotate的功能,具體要求如下:

1)要處理的日誌路徑:/data/logs/1.log

2)每天0點0分切割日誌

3)老日誌保留一週

4)歸檔後的日誌名字爲:1.log.1,1.log.2,... ,1.log.7

5)假設日誌歸檔後,新日誌可以自動生成


知識點一:logrotate

先聲明,本案例腳本並不會引用該部分知識點,在這裏僅做簡單介紹,下面通過一段配置解釋其含義。

/var/log/messages {    //日誌的路徑
       rotate  5       //保留5份歸檔後的日誌
       weekly          //一週切割一次
       postrotate      //定義切割日之後,要執行的指令
           /usr/bin/killall -HUP syslogd  //重載syslogd服務,這樣會生成新的/var/log/messages文件
       endscript       //表示執行shell命令到此結束    
}

  "/var/log/httpd/access.log" /var/log/httpd/error.log  {  //同時寫多個日誌的路徑
       rotate  5
       mail [email protected]  //把歸檔後的日誌發送給該郵箱
       size  100k       //當日志文件達到100k時開始做切割
       sharedscripts    //對於第一行定義的所有日誌來說,以下的shell命令(/usr/bin/killall -HUP httpd)只運行一次,而不是每切割一個日誌就執行一次。
       postrotate
            /usr/bin/killall -HUP httpd
       endscript     
  }
  
    /var/log/news/* {  //支持*通配
    monthly    //一個月切割一次日誌
    rotate  2  //保留2個歸檔日誌
    olddir /var/log/news/old  //將切割後的日誌保存到這個目錄下面
    missingok  //如果日誌文件丟失,不報錯
    postrotate
       kill -HUP 'cat /var/run/inn.pid'
    endscript
    nocompress  //歸檔後的日誌不壓縮,與其相對的參數是compress   
    }


知識點二:shell中的exit、break和continue

1)exit

在shell腳本中使用exit,則直接退出當前腳本,exit後續的所有指令都不再執行,示例腳本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

執行腳本,結果如下:

# sh exit.sh 
1
1
2
2
3

exit後面可以跟一個數字,表示該腳本的返回值,執行完腳本後,執行echo $?可以打印腳本的返回值。

# echo $?
1


2)break

在shell腳本的循環中,可以使用break跳出循環體,示例腳本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

執行腳本,結果如下:

# sh break.sh 
1
1
2
2
3
aaaaa

說明:當$i爲3時,遇到break指令,此時會跳出整個循環,從而執行echo  aaaaa指令。


3)continue

和break類似,continue的作用是結束本次循環,繼續下一次循環,而不會結束整個循環體,示例腳本continue.sh:

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

執行腳本,結果如下:

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

說明:當$i=3時,遇到continue指令,此時結束本次循環,即continue後面的指令echo $i不再執行,繼續後續循環,即i=4。


本案例參考腳本

#!/bin/bash
#日誌切割歸檔,按天切割,1.log變1.log.1, 1.log.1變1.log.2, ...
#作者:
#日期:

logdir=/data/logs/

#定義函數,如果一個文件存在,則刪除
function e_df()
{
    if [ -f $1 ]
    then
        rm -f $1
    fi
}

cd $logdir

#從7到2,依次遍歷循環
for i in `seq 7 -1 2`
do
    #$i2比$i小1
    i2=$[$i-1]
    
    #首先判斷1.log.7是否存在,若存在則刪除
    e_df  1.log.$i

    #當1.log.6存在,則把1.log.6改名爲1.log.7,依次類推
    if [ -f  1.log.$i2 ]
    then
        mv  1.log.$i2 1.log.$i
    fi
done

#由於1.log後面無後綴,所以不能走上面的for循環,只能另外拿出來處理
e_df 1.log.1
mv  1.log 1.log.1

##說明:這個腳本寫完後,放到任務計劃裏,每天0點0分執行。


需求擴展

現在的需求是,日誌按大小來切割,比如當日志大於等於100M時,則需要處理,處理後的日誌需要壓縮,並且延遲一天,即1.log.1不用壓縮,其他需要壓縮。

#!/bin/bash
#日誌切割歸檔,按日誌大小切割(100M),1.log變1.log.1, 1.log.1變1.log.2, ...
#作者:
#日期:

logdir=/data/logs/

#技術1.log大小
size=`du -sk $logdir/1.log |awk '{print $1}`

#如果1.log小於100M,則退出腳本
if [ $size -lt 10240 ]
then
    exit 0
fi

#定義函數,如果一個文件存在,則刪除
function e_df()
{
    if [ -f $1 ]
    then
        rm -f $1
    fi
}

cd $logdir

#如果1.log.1存在,則先把它壓縮爲1.log.1.gz,這樣下面的for循環纔不會出錯
if [ -f 1.log.1 ]
then
    gzip 1.log.1
fi
#由於1.log.1已經被壓縮爲1.log.gz,所以可以直接將1.log改名爲1.log.1
mv  1.log 1.log.1

#從7到2,倒序循環
for i in `seq 7 -1 2`
do
    #$i2比$i小1
    i2=$[$i-1]
    
    #首先判斷1.log.7.gz是否存在,若存在則刪除
    e_df  1.log.$i.gz

    #當1.log.6.gz存在,則把1.log.6.gz改名爲1.log.7.gz,依次類推
    if [ -f  1.log.$i2.gz ]
    then
        mv  1.log.$i2.gz 1.log.$i.gz
    fi
done

##說明:由於我們需要按照日誌大小切割,所以這個腳本寫完後,需要每分鐘執行一次。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章