案例十七:归档老日志

在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  //保留两个归档日志
           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, ...
#作者:阿铭
#日期:2018-11-1

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, ...
#作者:阿铭
#日期:2018-11-1

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

##说明:由于我们需要按照日志大小切割,所以这个脚本写完后,需要每分钟执行

版权声明:
作者:WaterBear
链接:https://l-t.top/2831.html
来源:雷霆运维
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>
文章目录
关闭
目 录