一、简介

Logrotate 程序是linux系统自带的一个日志文件管理工具。用于分割日志文件,压缩转存、删除旧的日志文件,并创建新的日志文件;而运维过程中,经常见我们对比如nginx,通过脚本的方式按天进行切割,logroate工具没有得到有效利用。

Linux切割java日志 linux自带日志切割_Linux切割java日志

logrotate旨在简化生成大量日志文件的系统的管理。它允许自动旋转、压缩、删除和邮寄日志文件。每个日志文件可以每天、每周、每月处理,或者当它变得太大时处理。通常,logrotate将作为每日cron作业运行,因其基于 crontab 运行的,所以这个时间点是由 crontab 控制的,计划每天运行的脚本位于 /etc/cron.daily/logrotate,crontab 会每天定时执行 /etc/cron.daily 目录下的脚本,而这个目录下有个文件叫 logrotate;除非该日志大小被固定限制,并且日志轮训每天运行一次以上,或者除非使用-f或–force选项,否则它将不会在一天内多次修改日志。

logrotate运行时,命令行如指定了一个目录,则该目录中的每个文件都将用作配置文件;

二、配置文件

通用的Linux系统默认安装logrotate工具,如果没有请手动安装,它默认的配置文件在:
/etc/logrotate.conf //主配置文件
/etc/logrotate.d/ //配置文件目录,该目录里的所有文件都会被主动的读入/etc/logrotate.conf中执行。

# 以下设定是 "logrotate 的默认值" ,如果別的文件设定了其他的值,
# 就会以其它文件的设定为主
weekly          //默认每一周执行一次rotate轮转工作
rotate 4       //保留多少个日志文件(轮转几次).默认保留四个.就是指定日志文件删除之前轮转的次数,0 指没有备份
create         //自动创建新的日志文件,新的日志文件具有和原来的文件相同的权限;因为日志被改名,因此要创建一个新的来继续存储之前的日志
dateext       //这个参数很重要!就是切割后的日志文件以当前日期为格式结尾,如xxx.log-20131216这样,如果注释掉,切割出来是按数字递增,即前面说的 xxx.log-1这种格式
compress      //是否通过gzip压缩转储以后的日志文件,如xxx.log-20131216.gz ;如果不需要压缩,注释掉就行
 
include /etc/logrotate.d   # 将 /etc/logrotate.d/ 目录中的所有文件都加载进来
 
/var/log/wtmp {                 //仅针对 /var/log/wtmp 所设定的参数
monthly                    //每月一次切割,取代默认的一周,daily,weekly
minsize 1M              //文件大小超过 1M 后才会切割
create 0664 root utmp            //指定新建的日志文件权限以及所属用户和组,权限是0664,所有者是root,所属组是utmp组
rotate 1                    //只保留一个日志,不设置就默认为1 , 即只会保存一个滚动压缩的文件和一个正在输出日志文件
}
# 这个 wtmp 可记录用户登录系统及系统重启的时间
# 因为有 minsize 的参数,因此不见得每个月一定会执行一次喔.要看文件大小。
/var/log/btmp {
#以下参数只对/var/log/btmp生效,lastb 命令查看的结果,记录错误登录的日志
missingok
#如果日志不存在,则忽略该日志的警告信患
monthly
create 0600 root utmp
rotate 1
}

注意:

1)配置文件里一定要配置 rotate 文件数目这个参数。如果不配置默认是 0 个,也就是只允许存在一份日志,刚切分出来的日志会马上被删除。
2) logrotate 命令执行最好加 -f 参数,不防止偶然配置文件修改的内容不生效情况。

由上可以知/etc/logrotate.d其实就是由/etc/logrotate.conf 所规划出来的目录,虽然可以将所有的配置都写入 /etc/logrotate.conf ,但是这样一来这个文件就变的太复杂,尤其是当使用很多的服务很多时,而在etc/logrotate.d/目录下,为想要分隔日志的服务单独创建一个目录,那么每个要切割日志的服务, 就可以独自成为一个文件,并且放置到 /etc/logrotate.d/ 当中。logrotate.d,这里存放了所有rpm安装程序的日志管理方式,非rpm安装的程序或者是开发出来业务程序一般都没有这些,需要自己加。

Linux切割java日志 linux自带日志切割_Linux切割java日志_02


/etc/logrotate.d/ 通常一些第三方软件包,或把自己私有的日志切割配置文件,也放到这个目录下。

配置文件其他配置项含义:

compress                            #通过gzip 压缩转储以后的日志
nocompress                          #不做gzip压缩处理
copytruncate                        #用于还在打开中的日志文件,把当前日志备份并截断;是先拷贝再清空的方式,拷贝和清空之间有一个时间差,可能会丢失部分日志数据。
nocopytruncate                      #备份日志文件不过不截断
create mode owner group             #轮转时指定创建新文件的属性,如create 0777 nobody nobody
nocreate                            #不建立新的日志文件
delaycompress                      #和compress 一起使用时,转储的日志文件到下一次转储时才压缩
nodelaycompress                    #覆盖 delaycompress 选项,转储同时压缩。
missingok                          #如果日志丢失,不报错继续滚动下一个日志
errors address                     #专储时的错误信息发送到指定的Email 地址
ifempty                            #即使日志文件为空文件也做轮转,这个是logrotate的缺省选项。
notifempty                         #当日志文件为空时,不进行轮转
mail address                       #把转储的日志文件发送到指定的E-mail 地址
nomail                             #转储时不发送日志文件
olddir directory                   #转储后的日志文件放入指定的目录,必须和当前日志文件在同一个文件系统
noolddir                           #转储后的日志文件和当前日志文件放在同一个目录下
sharedscripts                      #运行postrotate脚本,作用是在所有日志都轮转后统一执行一次脚本。如果没有配置这个,那么每个日志轮转后都会执行一次脚本
prerotate                          #在logrotate转储之前需要执行的指令,例如修改文件的属性等动作;必须独立成行
postrotate                         #在logrotate转储之后需要执行的指令,例如重新启动 (kill -HUP) 某个服务!必须独立成行
daily                              #指定转储周期为每天
weekly                             #指定转储周期为每周
monthly                            #指定转储周期为每月
rotate count                       #指定日志文件删除之前转储的次数,0 指没有备份,5 指保留5 个备份
dateext                            #使用当期日期作为命名格式
dateformat .%s                     #配合dateext使用,紧跟在下一行出现,定义文件切割后的文件名,必须配合dateext使用,只支持 %Y %m %d %s 这四个参数
size(或minsize) log-size           #当日志文件到达指定的大小时才转储,log-size能指定bytes(缺省)及KB (sizek)或MB(sizem).
当日志文件 >= log-size 的时候就转储。 以下为合法格式:(其他格式的单位大小写没有试过)
size = 5 或 size 5 (>= 5 个字节就转储)#满足size就滚动一次,size参数跟滚动周期参数:hourly、daily、monthly、yearly完全是互斥的。即一旦设置了size参数,滚动周期参数就自动无效了,只要每次执行logrotate指令时,日志文件大小超过size,就会触发一次滚动,没有滚动周期一说了
size = 100k 或 size 100k
size = 100M 或 size 100M
maxsize 100k    #一般用于多次轮询;当执行logrorate指令时,只要日志的大小超过100k,即使时间没到下一个滚动周期内,也会发生滚动。那么同一小时内0:00--0:59就会发生多次滚动。换句话说,如果demo.txt的大小一直没有达到maxsize,那么一个滚动周期就只会发生一次滚动,即当前滚动周期内第一次执行logrorate指令就会触发滚动。以后的59分钟都不会发生滚动。maxsize可以使滚动提前发生,再下一个滚动周期到来之前发生多次滚动。即每满足maxsize就滚动一次,不满足则滚动1次,(每个滚动周期内,n次或1次)
【maxsize size】: Log files are rotated when they grow bigger than size bytes even before the additionally specified time interval (daily, weekly, monthly, or yearly).  The related size  option is  similar except that it is mutually exclusive with the time interval options, and it causes log files to be rotated without regard for the last rotation time.  When maxsize is used, both the size and timestamp of a log file are considered.
minsize   100k     #一个滚动周期内只会发生一次滚动,在当前滚动周期后面的时间里,即使日志大小再次超过100k,也不会再发生滚动,即minsize不能使滚动提前发生。如果日志的大小一直没有达到minsize,那么这个滚动周期内是不会触发滚动的。即满足minsize则滚动一次,不满足则滚动0次,(每个滚动周期内,1次或0次)。
maxage  60     #自动删除掉超过maxage指定天数的切割后的归档文件,即最大保留60天;相对于rotate按文件数,它是以天数为单位的

其中注意以下3个选项:主要用于在日志轮替的同时执行指定的脚本,一般用于日志轮替之后重启服务

sharedscripts 在此关键宇之后的脚本只执行一次
prerotate/cndscript 在曰志轮替之前执行脚本命令。endscript标识prerotate脚本结束
postrolaie/endscripl 在日志轮替之后执行脚本命令。endscripi标识postrotate脚本结束

如果你的日志是写入 rsyslog 服务的配置文件的,那么把新日志加入 logrotate 后,一定要重启 rsyslog 服务,否则你会发现,虽然新日志建立了,但数据还是写入了旧的日志当中。那是因为虽然 logrotate 知道日志轮替了,但是 rsyslog 服务并不知道。对于源码包安装了 apache、Nginx 等服务,则需要重启 apache 或 Nginx 服务,同时还要重启 rsyslog 服务,否则日志也不能正常轮替。如下示例:

"/var/log/httpd/access.log" /var/log/httpd/error.log {
#日志轮替的是/var/log/httpd/中RPM包默认安装的apache正确访问日志和错误日志
    rotate 5
    #轮替5次
    mail www@my.org
    #把信息发送到指定邮箱
    size 100k
    #日志大于100KB时才进行日志轮替,不再按照时间轮替
    sharedscripts
    #以下脚本只执行一次
    postrotate
    #在日志轮替结束之后,执行以下脚本
    /usr/bin/killall -HUP httpd
    #重启apache 服务
endscript
#脚本结束
}

三、定时任务配置定期切割

系统自带 cron task:/etc/cron.daily/logrotate,每天运行一次。

#!/bin/sh

/usr/sbin/logrotate /etc/logrotate.conf
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
    /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit 0

Linux切割java日志 linux自带日志切割_shell切割脚本_03

四、手动执行切割日志

/

usr/sbin/logrotate -f /etc/logrotate.d/nginx			//-f是强制执行,立即截断
cat /var/lib/logrotate.status  #查看执行过程
/usr/sbin/logrotate -d -f /etc/logrotate.d/nginx			//-d是debug调试的意思,用以正式执行前验证切割效果,而不进行具体操作

命令语法: logrotate [OPTION…]

-d, --debug :debug模式,测试配置文件是否有错误。常用,在脚本执行前检验验证脚本运行情况,不会实际去切割日志
-f, --force :强制转储文件。
-m, --mail=command :压缩日志后,发送日志到指定邮箱。
-s, --state=statefile :使用指定的状态文件。
-v, --verbose :显示转储过程。

五、logrotate工作原理回顾

logrotate 是怎么做到滚动日志时不影响程序正常的日志输出呢?logrotate 提供了两种解决方案。

  1. create
  2. copy—>truncate

Linux 文件系统里文件和文件名的关系如下图:

Linux切割java日志 linux自带日志切割_python切割脚本_04


目录也是文件,文件里存着文件名和对应的 inode 编号。通过这个 inode 编号可以查到文件的元数据和文件内容。文件的元数据有引用计数、操作权限、拥有者 ID、创建时间、最后修改时间等等。文件件名并不在元数据里而是在目录文件中。因此文件改名、移动,都不会修改文件,而是修改目录文件。

进程打开文件的机制:

Linux切割java日志 linux自带日志切割_日志切割_05


进程每新打开一个文件,系统会分配一个新的文件描述符给这个文件。文件描述符对应着一个文件表。表里面存着文件的状态信息(O_APPEND/O_CREAT/O_DIRECT…)、当前文件位置和文件的 inode 信息。系统会为每个进程创建独立的文件描述符和文件表,不同进程是不会共用同一个文件表。正因为如此,不同进程可以同时用不同的状态操作同一个文件的不同位置。文件表中存的是 inode 信息而不是文件路径,所以文件路径发生改变不会影响文件操作。

1、create

这也就是默认的方案,通过 create 命令配置文件的权限和属组设置;其是就是重命名原日志文件,创建新的日志文件。详细步骤如下:
1)重命名正在输出日志文件,因为重命名只修改目录以及文件的名称,而进程操作文件使用的是 inode,所以并不影响原程序继续输出日志。
2)创建新的日志文件,文件名和原日志文件一样,注意,此时只是文件名称一样,而 inode 编号不同,原程序输出的日志还是往原日志文件输出。
3)最后通过某些方式通知程序,重新打开日志文件;由于重新打开日志文件会用到文件路径而非 inode 编号,所以打开的是新的日志文件。

如上也就是 logrotate 的默认操作方式,也就是 mv+create 执行完之后,通知应用重新在新文件写入即可。mv+create 成本都比较低,几乎是原子操作,如果应用支持重新打开日志文件,如 syslog, nginx, mysql 等,那么这是最好的方式。

不过,有些程序并不支持这种方式,压根没有提供重新打开日志的接口;而如果重启应用程序,必然会降低可用性,为此引入了如下方式。

2、copytruncate

本方案是把正在输出的日志拷 (copy) 一份出来,再清空 (trucate) 原来的日志;详细步骤如下:

1)将当前正在输出的日志文件复制为目标文件,此时程序仍然将日志输出到原来文件中,此时,原文件名也没有变。
2)清空日志文件,原程序仍然还是输出到预案日志文件中,因为清空文件只把文件的内容删除了,而 inode 并没改变,后续日志的输出仍然写入该文件中。

如上所述,对于 copytruncate 也就是先复制一份文件,然后清空原有文件。

通常来说,清空操作比较快,但是如果日志文件太大,那么复制就会比较耗时,从而可能导致部分日志丢失。不过这种方式不需要应用程序的支持即可。

/data/nginx_logs/*.access_log       
{
nocompress                                  
daily                                 
copytruncate     ##不重启应用                           
create                             
ifempty                                  
olddir /data/nginx_logs/days          
rotate 0                                       
}

六、日志切割实例应用参考

实例1: 切割nginx日志

vim /etc/logrotate.d/nginx

/usr/local/nginx/logs/*.log {
daily
rotate 7
missingok
notifempty
dateext
sharedscripts
postrotate
    if [ -f /usr/local/nginx/logs/nginx.pid ]; then
        kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`
    fi
endscript
}

vim /etc/logrotate.d/nginx

/data/nginx_logs/*.access_log       
{
nocompress                                  
daily                                 
copytruncate                                 
create                             
ifempty                                  
olddir /data/nginx_logs/days          
rotate 0                                       
}

如果脚本的话:vim /usr/local/sbin/logrotate-nginx.sh

#!/bin/bash
#创建转储日志压缩存放目录
mkdir -p /data/nginx_logs/days
#手工对nginx日志进行切割转换
/usr/sbin/logrotate -vf /etc/logrotate.d/nginx
#当前时间
time=$(date -d "yesterday" +"%Y-%m-%d")
#进入转储日志存放目录
cd /data/nginx_logs/days
#对目录中的转储日志文件的文件名进行统一转换
for i in $(ls ./ | grep "^\(.*\)\.[[:digit:]]$")
do
mv ${i} ./$(echo ${i}|sed -n 's/^\(.*\)\.\([[:digit:]]\)$/\1/p')-$(echo $time)
done
#对转储的日志文件进行压缩存放,并删除原有转储的日志文件,只保存压缩后的日志文件。以节约存储空间
for i in $(ls ./ | grep "^\(.*\)\-\([[:digit:]-]\+\)$")
do
tar jcvf ${i}.bz2 ./${i}
rm -rf ./${i}
done
#只保留最近7天的压缩转储日志文件
find /data/nginx_logs/days/* -name "*.bz2" -mtime 7 -type f -exec rm -rf {} \;

完成后,crontab -e
#logrotate
0 0 * * * /bin/bash -x /usr/local/sbin/logrotate-nginx.sh > /dev/null 2>

早期脚本实现:vim /root/Ywei/cut_nginx_log.sh

#!/bin/bash
# 你的日志文件存放目录
logs_path="/usr/local/nginx/logs/"
# 日志文件的名字,多个需要空格隔开
logs_names=(error access pv_access)
dates=`date -d "yesterday" +"%Y%m%d"`
#或dates=$(date -d "yesterday" +%Y-%m-%d)
mkdir -p ${logs_path}$dates/
num=${#logs_names[@]}
for((i=0;i<num;i++));do
mv ${logs_path}${logs_names[i]}.log ${logs_path}$dates/${logs_names[i]}.log
done
#nginx平滑重启
kill -USR1 `cat /var/run/nginx/nginx.pid`

结合crontab定时执行:crontab -e
#nginx日志切割
00 00 * * * cd /usr/local/nginx/logs/;/bin/bash /root/Ywei/cut_nginx_log.sh > /dev/null 2>$1

方式3:python脚本实现,参考如下

import os, sys, datetime,re
 
# nginx日志存放的路径
nginxLogPath="/usr/local/nginx/logs/"
# 获取昨天的日期
yesterday = (datetime.date.today() + datetime.timedelta(days = -1)).strftime("%Y-%m-%d")
# nginx启动的pid文件
PID = "/var/run/nginx.pid"
 
def cutNginxLog(path):
    """
    切割nginx日志函数
    :param path: 日志文件的第一级目录
    :return: 
    """
    logList = os.listdir(path)    # 判断传入的path是否是目录
    for logName in logList:      # 循环处理目录里面的文件
        logAbsPath = os.path.join(path, logName)
        if os.path.isdir(logAbsPath):   # 如果是目录,递归调用自己,继续处理
            cutNginxLog(logAbsPath)
        else:         # 如果是日志文件,就进行处理
            # 分割日志
            re_Num = re.compile(r'^[a-zA-Z]')
            # 判断日志文件是否是字母开头,如果是日期开头就不切割
            if re_Num.search(logName):
                logNewName = yesterday + "_" + logName          # 新日志文件名称列如:2020-11-8_access.log
                oldLogPath = os.path.join(path, logName)        # 旧日志文件绝对路径
                newLogPath = os.path.join(path, logNewName)     # 新日志文件绝对路径
                os.rename(oldLogPath, newLogPath)
 
    cmd = " kill -USR1 `cat %s` "% PID
    res = os.system(cmd)
    if res != 0:
        return "重新加载nginx失败"
cutNginxLog(nginxLogPath)

结合crontab定时执行:crontab -e
#nginx日志切割
00 00 * * * cd /usr/local/nginx/logs/;/usr/bin/python3.5 /root/Ywei/cut_nginx_log.py > /dev/null 2>$1

实例2: 切割php日志:
vim /etc/logrotate.d/php

/Data/logs/php/*log {
    daily
    rotate 365
    missingok
    notifempty
    compress
    dateext
    sharedscripts
    postrotate
        if [ -f /Data/app/php5.6.26/var/run/php-fpm.pid ]; then
            kill -USR1 `cat /Data/app/php5.6.26/var/run/php-fpm.pid`
        fi
    endscript
    postrotate
        /bin/chmod 644 /Data/logs/php/*gz
    endscript
}

实例3: syslog切割
vim /etc/logrotate.d/syslog

/var/log/cron
/var/log/maillog
/var/log/messages
/var/log/secure
/var/log/spooler
{
    sharedscripts
    postrotate
    /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
    endscript
}

实例4:tomcat日志切割
vim /etc/logrotate.d/tomcat

/Data/app/tomcat-7-huanqiu/logs/catalina.out {
rotate 14
daily
copytruncate
compress
notifempty
missingok
}

实例4:切割其他自定义日志:/etc/logrotate.d/alter

/var/log/alert.log {
    weekly
    #每周轮替一次
    rotate 6
    #保留6个轮替曰志
    dateext
    dateformat .%Y%m%d   #只支持年月日时
    sharedscripts  #引入脚本,以下命令只执行一次
    prerotate
    #在日志轮替之前执行
        /usr/bin/chattr -a /var/log/alert.log
        #在日志轮替之前取消a属性,以便让日志可以轮替
    endscript
    #脚本结朿
    sharedscripts
    postrotate
    #在日志轮替之后执行
        /usr/bin/chattr +a /var/log/alert.log
        #在日志轮替之后,重新加入a属性
    endscript
    lastaction  #备份日志,按时间重命名
    	name=$(ls -t /data/log_bak/test/ | head -n 1)
    	dat=$(echo $name | awk -F. '{print $(NF-1)}')
    	minute=$(date +%H%M)
    	newname=$(echo $name | sed 's/'$dat'/'$dat'-'$minute'/g')
    	mv /data/log_bak/test/$name /data/log_bak/test$newname
    endscript
    sharedscripts
    postrotate
    /bin/kill -HUP $(/bin/cat /var/run/syslogd.pid 2>/dev/null) fi>/dev/null
    endscript
    #重启rsyslog服务,保证日志轮替正常进行
}

七、附:其他日志切割方式

示例1: Python脚本实现日志切割

#!/usr/bin/env python
 
import datetime,os,sys,shutil
 
log_path = '/opt/jumpserver/logs/'
log_file = 'jumpserver.log'
 
yesterday = (datetime.datetime.now() - datetime.timedelta(days = 1))
 
try:
    os.makedirs(log_path + yesterday.strftime('%Y') + os.sep + \
                yesterday.strftime('%m'))
 
except OSError,e:
    print
    print e
    sys.exit()
 


shutil.move(log_path + log_file,log_path \
            + yesterday.strftime('%Y') + os.sep \
            + yesterday.strftime('%m') + os.sep \
            + log_file + '_' + yesterday.strftime('%Y%m%d') + '.log')
 
 
os.popen("sudo /opt/jumpserver/service.sh restart")

定时任务:30 1 * * * /usr/bin/python /mnt/log_rotate.py > /dev/null 2>&1

示例2:对nginx日志进行切割

#!/usr/bin/env python
 
import datetime,os,sys,shutil
 
log_path = '/app/nginx/logs/'
log_file = 'www_access.log'
 
yesterday = (datetime.datetime.now() - datetime.timedelta(days = 1))
 
try:
    os.makedirs(log_path + yesterday.strftime('%Y') + os.sep + \
                yesterday.strftime('%m'))
 
except OSError,e:
    print
    print e
    sys.exit()
 
 
shutil.move(log_path + log_file,log_path \
            + yesterday.strftime('%Y') + os.sep \
            + yesterday.strftime('%m') + os.sep \
            + log_file + '_' + yesterday.strftime('%Y%m%d') + '.log')
 
 
os.popen("sudo kill -USR1 `cat /app/nginx/logs/nginx.pid`")

示例3:shell脚本实现日志切割

!/bin/sh
 
function rotate() {
logs_path=$1
 
echo Rotating Log: $1
cp ${logs_path} ${logs_path}.$(date -d "yesterday" +"%Y%m%d")
> ${logs_path}
    rm -f ${logs_path}.$(date -d "7 days ago" +"%Y%m%d")
}
 
for i in $*
do
        rotate $i
done

定时任务;30 0 * * * find /data/log/xcspam/ -size +0 -name ‘.log’ | xargs /app/script/log_rotate.sh
手动验证:find /data/log/xcspam/ -size +0 -name '
.log’ | xargs /app/script/log_rotate.sh

nginx切割日志:

#!/bin/bash
 
yesterday=`date -d "-1 days" +'%Y%m%d'`
cd `dirname $0`
basedir=`pwd`
logdir="${basedir}/bak"
bindir="${basedir%/*}/sbin"
mkdir -p ${logdir}
 
for log in `ls *.log 2>/dev/null`
do
    mv ${log} ${logdir}/${log}.${yesterday}.bak
    # gzip ${logdir}/${log}.${yesterday}
done
 
${bindir}/nginx -s reload
 
cd ${logdir}
find . -type f -name "*.bak" -mtime +7 | xargs rm -f

示例4:日志压缩脚本:

#!/usr/bin/sh
#根据系统/服务/日志保留天数三个参数压缩日志
#usage: sh clearlog.sh sysname appname keepdays
sysName=$1
appName=$2
keepDay=$3
logDir=/var/log/${sysName}/${appName}
logFile=${appName}.*[0-9][0-9].log
cd ${logDir}
find ./ -name "${logFile}" -mtime -${keepDay} -exec gzip {} \;

参考:https://www.linuxidc.com/Linux/2019-02/157099.htm

示例5:sed截取/切割日志

#截取某时间到到结尾的行,要求输入的日期必须要真实存在
sed -n '/22-12-1/,$p' ./logs/catalina.out > /tmp/2212.log
sed -n "/04\/Apr\/2016/,/05\/Apr\/2016/"p access.log > test.log
sed -n '/2020-04-09T16:48:10.906/,/2020-04-09T16:48:11.070/p' access.log > test.log
#截取某时间段
sed -n '/2022-05-04 09:25:55/,/2022-05-04 09:28:55/p' logfile
sed -n '/2022-11-17 09:[0-9][0-9]:[0-9][0-9]/,/2022-11-17 16:[0-9][0-9]:[0-9][0-9]/p'  logfile
sed -i   '/2022-11-17 09:[0-9][0-9]:[0-9][0-9]/,/2022-11-17 16:[0-9][0-9]:[0-9][0-9]/d'  logfile  #删除
#截取第几行到第几行
sed -n '1,5000p' ./logs/catalina.out > /tmp/5000.log
sed -i   '1,5000d' a.txt  #删除

删除第2~5行
#脚本示例:截取后清空
 #!/bin/bash

monday_year=$(date -d 'last monday' +"%Y")
f_monday_month=$(date -d 'last monday' +"%m")
monday_day=$(date -d 'last monday' +"%d")

now_year=$(date -d 'now' +"%Y")
f_now_month=$(date -d 'now' +"%m")
now_day=$(date -d 'now' +"%d")

#filename_day=$monday_year$f_now_month$monday_day'-'$now_year$f_now_month$now_day
filename_day=$now_year$f_now_month$now_day
echo $filename_day

echo 1
#access
if test -s /usr/local/nginx/logs/access.log ;
then
filename=$filename_day
cp /usr/local/nginx/logs/access.log /var/www/html/logs_backup/access/$filename.log
zcat -f /var/www/html/logs_backup/access/$filename.log | /usr/local/bin/goaccess -a -p /root/.goaccessrc > /var/www/html/logs_html/access/$filename.html
fi
log_report/goaccess_log.sh

更多参看:http://www.taodudu.cc/news/show-3564800.html?action=onClick

示例6:split切割

#每300行切分生成一个新文件,–verbose 显示切分进度

split -l 300 java.txt javaLog --verbose

#每10M切分成一个新的文件,–verbose 显示切分进度

split -d 10m java.txt javaLog --verbose

示例7:java项目log4j配置的切割

#springBoot项目

#引入log4j依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-to-slf4j</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>crm-api
    <version>2.17.1</version>
    <exclusions>
        <exclusion>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.1</version>
</dependency>

#配置yml
logging:
  level:
    com.alibaba.nacos.client.naming: error #错误日志
    com.xxx.xxxx: DEBUG #业务日志
    org.hibernate.SQL: DEBUG  #SQL打印
  file:
    path: /data/logs/${spring.application.name} #存放路径
#logback配置
<?xml version="1.0" encoding="UTF-8"?>

<configuration debug="false">
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->  
    <property name="LOG_PATH" value="${LOG_HOME}/logs" />
    <!-- 控制台输出 -->   
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> 
             <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> 
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>   
        </encoder> 
    </appender>
    <!-- 按照每天生成日志文件 -->   
    <appender name="FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">   
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_PATH}/dialup.%d{yyyy-MM-dd}.%i.log.gz</FileNamePattern> 
            <!--日志文件保留天数-->
            <MaxHistory>180</MaxHistory>
            <!-- 日志最大的文件兆 100MB             -->
            <maxFileSize>100MB</maxFileSize> 
            <totalSizeCap>500GB</totalSizeCap> 
        </rollingPolicy>   
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> 
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> 
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>   
        </encoder> 
    </appender> 
    <!-- 日志级别排序为: TRACE < DEBUG < INFO < WARN < ERROR -->
    <root level="INFO">
        <appender-ref ref="STDOUT"/><!--日志输出到控制台  -->
        <appender-ref ref="FILE"/><!-- 日志输出到日志文件 -->
    </root>
    <!-- 开发、测试环境 -->
    <springProfile name="dev,test,testlocal,collect-north,collect-south,prod">
	    <logger name="org.springboot.sample" level="info" additivity="false">
	        <appender-ref ref="FILE" />
	    </logger>
	    <logger name="org.springframework.web" level="info" additivity="false">
	        <appender-ref ref="FILE" />
	    </logger>
	    <logger name="com.bjbt" level="debug" additivity="false">
	        <appender-ref ref="FILE" />
	        <appender-ref ref="STDOUT" />
	    </logger>
    </springProfile>
</configuration>

#网络示例
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">

    <conversionRule conversionWord="clr"
                    converterClass="org.springframework.boot.logging.logback.ColorConverter" />
    <conversionRule conversionWord="wex"
                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
    <conversionRule conversionWord="wEx"
                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
    <springProperty scope="context" name="LOG_PATH" source="logging.file.path"/>
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-
%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-
%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39})
{cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
    <property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-
yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} :
%m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
    <property name="FILE_LOG_ACTION_PATTERN" value="${FILE_LOG_ACTION_PATTERN:-
%m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
    <!-- 控制台日志 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>
    <!-- 全量日志 -->
    <appender name="FILE_ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder><pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>
        <file>${LOG_PATH}/all.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/all.log.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
            <maxFileSize>${LOG_FILE_MAX_SIZE:-50MB}</maxFileSize>
            <maxHistory>${LOG_FILE_MAX_HISTORY:-0}</maxHistory>
        </rollingPolicy>
    </appender>
    <!-- 错误日志 -->
    <appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>
        <file>${LOG_PATH}/err.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/err.log.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
            <maxFileSize>${LOG_FILE_MAX_SIZE:-50MB}</maxFileSize>
            <maxHistory>${LOG_FILE_MAX_HISTORY:-0}</maxHistory>
        </rollingPolicy>
        <!-- 过滤出ERROR级别的日志 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 访问日志 -->
    <appender name="FILE_LOG_ACTION" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>${FILE_LOG_ACTION_PATTERN}</pattern>
        </encoder>
        <file>${LOG_PATH}/action.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/action.log.%d{yyyy-MM-dd}.%i.gz</fileNamePattern>
            <maxFileSize>${LOG_FILE_MAX_SIZE:-50MB}</maxFileSize>
            <maxHistory>${LOG_FILE_MAX_HISTORY:-0}</maxHistory>
        </rollingPolicy>
    </appender>

    <!-- 日志总开关 -->
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE_ALL" />
        <appender-ref ref="FILE_ERROR" />
    </root>
    <logger name="ActionLog" level="INFO" additivity="false">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE_LOG_ACTION" />
    </logger>
    <!-- 日志过滤 -->
    <logger name="org.apache.catalina.startup.DigesterFactory" level="ERROR"/>
    <logger name="org.apache.catalina.util.LifecycleBase" level="ERROR"/>
    <logger name="org.apache.coyote.http11.Http11NioProtocol" level="WARN"/>
    <logger name="org.apache.sshd.common.util.SecurityUtils" level="WARN"/>
    <logger name="org.apache.tomcat.util.net.NioSelectorPool" level="WARN"/>
    <logger name="org.eclipse.jetty.util.component.AbstractLifeCycle" level="ERROR"/>
    <logger name="org.hibernate.validator.internal.util.Version" level="WARN"/>
</configuration>

Linux切割java日志 linux自带日志切割_shell切割脚本_06

#log4j.properties配置中添加如下配置

log4j.rootLogger = INFO, A1, D, D1

######ConsoleAppender###############
log4j.appender.A1=org.apache.log4j.ConsoleAppender 
log4j.appender.A1.layout=org.apache.log4j.PatternLayout 
log4j.appender.A1.layout.ConversionPattern=%d %p %c.%M():%L - %m%n


#######DailyRollingFileAppender - INFO##################
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = ${catalina.base}/log/log
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.DatePattern = '.'yyyy-MM-dd'.log'
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern=%d %p %c.%M():%L - %m%n
#######DailyRollingFileAppender - ERROR##################
log4j.appender.D1 = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D1.File = ${catalina.base}/log/error
log4j.appender.D1.Threshold = ERROR
log4j.appender.D1.DatePattern = '.'yyyy-MM-dd'.log'
log4j.appender.D1.layout = org.apache.log4j.PatternLayout
log4j.appender.D1.layout.ConversionPattern=%d %p %c.%M():%L - %m%n