案例十7、归档老日志

Linux系统中有日志切割的工具logrotate,它能够按照咱们的预期按时间或者大小来切割和归档老的日志,它还能够压缩切割后的日志,也能够定义老日志保留的时间。shell

本案例的需求是用shell脚原本实现相似logrotate的功能,具体要求以下:bash

1)要处理的日志路径:/data/logs/1.logide

2)天天0点0分切割日志函数

3)老日志保留一周工具

4)归档后的日志名字为:1.log.1,1.log.2,... ,1.log.7post

5)假设日志归档后,新日志能够自动生成spa


知识点一:logrotate日志

先声明,本案例脚本并不会引用该部分知识点,在这里仅作简单介绍,下面经过一段配置解释其含义。ip

/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 www@my.org  //把归档后的日志发送给该邮箱
       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和continueit

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

##说明:因为咱们须要按照日志大小切割,因此这个脚本写完后,须要每分钟执行一次。