Nginx利用Logrotate实现日志分割


Posted in Servers onMay 20, 2022

前言

nginx默认没有提供对日志文件的分割功能,所以随着时间的增长,access.log和error.log文件会越来越大,尤其是access.log,其日志记录量比较大,更容易增长文件大小,影响日志写入性能

分割nginx日志的方法有很多,这里推荐利用Logrotate来完成

Logrotate用法

1.安装

logrotate是一个linux系统日志的管理工具。可以对单个日志文件或者某个目录下的文件按时间/大小进行切割,压缩操作;指定日志保存数量;还可以在切割之后运行自定义命令

logrotate是基于crontab运行的,所以这个时间点是由crontab控制的,具体可以查询crontab的配置文件/etc/anacrontab。系统会按照计划的频率运行logrotate,通常是每天。在大多数的Linux发行版本上,计划每天运行的脚本位于/etc/cron.daily/logrotate

主流Linux发行版上都默认安装有logrotate包,如果你的linux系统中找不到logrotate, 可以使用apt-get或yum命令来安装

yum install -y logrotate

一般linux都已经自带logrotate,下列命令可以查看是否已安装

rpm -ql logrotate

Nginx利用Logrotate实现日志分割

2.基本用法详解

2.1 入门

/etc/logrotate.conf这个文件是logrotate的主配置文件

# see "man logrotate" for details
# rotate log files weekly
weekly

# keep 4 weeks worth of backlogs
rotate 4

# create new (empty) log files after rotating old ones
create

# use date as a suffix of the rotated file
dateext

# uncomment this if you want your log files compressed
#compress

# 包含自定义配置目录
include /etc/logrotate.d

# no packages own wtmp and btmp -- we'll rotate them here
/var/log/wtmp {
    monthly
    create 0664 root utmp
        minsize 1M
    rotate 1
}

/var/log/btmp {
    missingok
    monthly
    create 0600 root utmp
    rotate 1
}

# system-specific logs may be also be configured here.

这个主配置文件中定义了日志文件分割的通用参数。并且include /etc/logrotate.d表示其会加载/etc/logrotate.d的所有自定义配置文件,自定义配置文件中的配置可以覆盖掉通用配置

我们来到自定义配置文件的目录/etc/logrotate.d

Nginx利用Logrotate实现日志分割

尝试在该目录中创建一个日志分割配置test,对/opt/logtest目录中所有以.log结尾的文件进行分割

vim test

# test配置文件的内容
/opt/logtest/*.log {
    daily
    rotate 2
    copytruncate
    missingok
}

test配置的第一行指定要对哪个路径的哪些文件进行分割,然后携带的4个参数解释如下:

  • daily:按天切割。触发切割时如果时间不到一天不会执行切割。除了daily,还可以选monthly,weekly,yearly
  • rotate:对于同一个日志文件切割后最多保留的文件个数
  • copytruncate:将源日志文件切割成新文件后,清空并保留源日志文件。默认如果不启用该配置,分割后源日志文件将被删除。设置该值,以便分割后可以继续在源日志文件写入日志,等待下次分割
  • missingok:切割中遇到日志错误忽略

创建好配置以后,系统会在每天利用cron定时执行logrotate日志分割指令。这里我们为了看到效果,不等到系统自动执行,可以手动强制执行一次日志分割。强制执行会立即进行一次日志

# -v:显示执行日志
# -f:强制执行分割
logrotate -vf /etc/logrotate.d/test

执行前,事先在日志所在目录中创建2个测试日志文件

touch test1.log
touch test2.log

手动执行一次日志分割,观察执行日志可以发现,过程如下:

  • 先将源日志内容拷贝到分割后的文件
  • 清空源文件

Nginx利用Logrotate实现日志分割

此时分割后的文件名为源文件名后面加上.序号,序号从1开始

Nginx利用Logrotate实现日志分割

然后我们再次手动执行一次分割,此时执行过程如下:

  • 将第一次分割后的日志文件test1.log.1重命名为test1.log.2
  • 将源日志文件拷贝到此次分割后的文件,命名序号重新从1开始,为test1.log.1
  • 清空源日志文件

Nginx利用Logrotate实现日志分割

Nginx利用Logrotate实现日志分割

接着再次手动执行一次分割,此时执行过程如下:

  • 将之前分割后的日志文件test1.log.2重命名为test1.log.3,test1.log.1重命名为test1.log.2
  • 分割源日志文件,拷贝其内容到test1.log.1
  • 由于设置了rotate为2,即最多保留2个日志文件,所以此时要删除最早分割出的那个日志文件,即test1.log.3

Nginx利用Logrotate实现日志分割

Nginx利用Logrotate实现日志分割

总结一下logrotate日志分割的步骤:

1.默认分割后日志的命名为源日志名称+.序号(从1开始)。分割之前将所有之前分割出的日志文件重命名,序号往后移一位
2.执行分割,将源日志文件分割为源日志文件名.1。这样就保证了所有分割后的文件中,序号最小的是最新分割出的,序号最大的是最早分割出的
3.根据rotate设置,如果此次分割后文件数量大于rotate设置,那么删除序号最大的那个分割文件,也就是最旧的分割日志

实际开发中可以使用create代替copytruncate,它们的区别如下:

copytruncate先将源文件内容拷贝到分割后文件,再清空源文件,拷贝和清空之间有时间差,可能会丢失部分日志。另外拷贝操作在源文件比较大时消耗性能

create直接将源文件重命名为分割后文件,再创建一个与源文件名称相同的新文件,用于后续日志写入

/opt/logtest/*.log {
    daily
    rotate 2
    create  # 创建与源文件名称相同的新文件,用于后续日志写入,新文件的归属用户、权限与源文件相同
    missingok
}

Nginx利用Logrotate实现日志分割

但是要注意create即使创建新的文件后,如果没有主动通知应用程序,那么应用程序仍然会往旧的文件(即被重命名的那个分割后的文件)写入日志。所以此时在分割后要通知应用程序重新打开新的日志文件进行写入。以通知nginx为例,配置如下

/var/log/nginx/*.log {
    daily                      
    rotate 30              
    create
    sharedscripts              # 所有的文件切割之后只执行一次下面脚本,通知nginx重新打开新的日志文件进行后续写入
    postrotate
        if [ -f /run/nginx.pid ]; then
            kill -USR1 `cat /run/nginx.pid`  # 通过USER1信号通知nginx重新打开日志文件
        fi
    endscript
}

综上,一般情况下如果应用程序提供了通知其打开新的日志文件的接口,那么推荐使用create续写日志;否则推荐使用copytruncate续写日志

注意:

  • /etc/logrotate.d中的自定义配置中,如果不配置rotate、daily等参数在强制手动执行时并不会继承默认的主配置/etc/logrotate.conf。比如不配置rotate时,并不会继承保留4个分割文件,而是等价于0,即不保留任何分割文件。所以自定义配置中推荐显式指定这些参数
  • 在系统crontab定时任务自动执行logrotate时,自定义配置会继承主配置文件中的参数
  • logrotate执行分割的时机要依赖于crontab定时任务,也就是说crontab定时任务每日触发时,logrotate才会读取相应配置,检查是否满足分割的条件决定是否执行分割。这意味着,在默认crontab每日触发logrotate的定时任务情况下,即便logrotate配置文件中配置的分割频率小于1天,也将按照1天的频率触发分割,除非修改crontab定时任务,将logrotate的任务触发频率修改为小于1天

2.2 分割文件压缩

我们可以通过如下设置对分割后的日志文件开启压缩

/opt/logtest/*.log {
    daily
    rotate 2
    copytruncate
    missingok
    compress           # 以gzip方式压缩
    nodelaycompress    # 所有分割后的文件都进行压缩
}

此时删除原有所有文件,重新创建测试日志文件test1.log和test2.log,然后手动执行分割,可以生成压缩后的.gz文件

Nginx利用Logrotate实现日志分割

一般可以将nodelaycompress改为delaycompress,这样分割后对最新的序号为1的文件不会进行压缩,对其他序号的文件进行压缩,这样可以方便我们查看最新的分割日志

Nginx利用Logrotate实现日志分割

2.3 按照时间分割

按照时间分割可以定时分割出一个日志,比如每天分割一次,配合其他参数可以完成保留最近n天日志的功能。以下配置可以实现每天分割一次日志,并且保留最近30天的分割日志

/opt/logtest/*.log {
    daily      # 每天分割一次
    rotate 30  # 保留最近30个分割后的日志文件
    copytruncate
    missingok
    dateext  # 切割后的文件添加日期作为后缀
    dateyesterday # 配合dateext使用,添加前一天的日期作为分割后日志的后缀
}

还是先删除原来的所有文件,重新创建

touch test{1,2}.log

再手动执行分割,此时生成的分割后的文件将不再以序号作为文件名结尾,而是以昨天的日期作为结尾

Nginx利用Logrotate实现日志分割

并且如果马上再手动执行一次分割,由于日期相同,不会像原来一样生成序号递增的新日志文件,此时相当于没有执行任何分割操作。即同一天只能分割一次,第二天再次执行才会分割出新的日期结尾的文件,所以此时设置rotate的值即为保留最近多少天日志的意思

Nginx利用Logrotate实现日志分割

此外,默认添加的日期后缀格式为yyyyMMdd,可以用dateformat自定义

/opt/logtest/*.log {
    daily      # 每天分割一次
    rotate 30  # 保留最近30个分割后的日志文件
    copytruncate
    missingok
    dateext  # 切割后的文件添加日期作为后缀
    dateyesterday # 配合dateext使用,添加前一天的日期作为分割后日志的后缀
    dateformat -%Y-%m-%d  # 格式为2022-02-08
}

2.4 按照文件大小分割

我们可以利用size配置指定当日志文件达到多大体积时才进行分割。以下配置指定了每天执行分割,但是只有当日志文件大于5M时才真正执行分割操作

/opt/logtest/*.log {
    daily      # 每天分割一次
    size 5M    # 源文件小于5M时不分割
    rotate 30  # 保留最近30个分割后的日志文件
    create
    missingok
    dateext  # 切割后的文件添加日期作为后缀
    dateyesterday # 配合dateext使用,添加前一天的日期作为分割后日志的后缀
}

注意:这个配置并不是说日志文件达到指定大小就自动执行分割,它还是要遵循定时任务。比如配置了daily只有到每天指定时间执行分割任务时,才会检查文件大小,对超过指定大小的文件进行分割

2.5 自定义每小时分割

logrotate实现每日定时执行日志分割的原理是通过cron定时任务,默认在/etc/cron.daily中包含logrotate可执行命令,所以系统每天会定时启动logrotate,然后它会根据配置中具体分割频率(daily、weekly等)以及其他条件(比如size)决定是否要真正执行分割操作

Nginx利用Logrotate实现日志分割

如果我们想要实现每小时进行一次分割,需要如下步骤:

  1. logrotate配置文件中指定分割频率为hourly
  2. 配置完以后,还需要在cron的每小时定时任务中加入logrotate,因为默认情况下只有/etc/cron.daily中包含logrotate可执行命令,我们要将它往/etc/cron.hourly中也拷贝一份,这样系统才会每小时调用一次logrotate去执行分割
cp /etc/cron.daily/logrotate /etc/cron.hourly/

2.6 自定义分割执行时间

logrotate 是基于cron 运行的,所以这个时间是由 cron 控制的,具体可以查询 cron 的配置文件/etc/crontab 。旧版CentOS 的cron 的配置文件是 /etc/crontab ,新版CentOS 改为 /etc/anacrontab

Nginx利用Logrotate实现日志分割

从上面的内容可以看出:

  • 如果机器 没有关机,默认 logrotate(配置文件里设置的是cron.daily)一般会在每天的3点05分到3点50分之间执行, 真实的延迟时间是RANDOM_DELAY + delay in minutes
  • 如果在3-22 这个时间段内服务器处于 关机状态,则 logrotate 会在机器开机5分钟后执行分割日志的操作

如果我们觉得每天凌晨3点多执行日志分割不合适,那么可以自定义分割执行时间。实现方式可以是:

  • 修改/etc/anacrontab中的定时执行时间,实际不推荐,可能会影响系统其他定时任务
  • 在/etc/logrotate.d以外的其他目录创建logrotate配置文件,然后利用crontab自定义cron表达式来执行logrotate对该配置进行分割操作

推荐采用crontab方式自定义执行时间,步骤如下:

在非/etc/logrotate.d目录创建logrotate配置文件,这是为了避免被系统的定时任务扫描到该配置而导致重复执行分割

添加 crontab 计划任务,在 root 用户下执行crontab -e进入 vim 模式,进行编辑

crontab -e
# 每天 23点59分进行日志切割
59 23 * * * /usr/sbin/logrotate -f /etc/logrotate_mytime/nginx

重启crontab

# centos6: 
service crond restart

# centos7: 
systemctl restart crond

nginx日志分割步骤

在/etc/logrotate.d中创建文件nginx,作为nginx日志分割的配置文件。指定每天执行一次分割,并且当文件大于5M时才进行分割。同时指定notifempty,当日志文件为空时不分割

/opt/docker-ws/nginx/logs/*.log {
    daily      # 每天分割一次
    size 5M    # 源文件小于5M时不分割
    rotate 30  # 保留最近30个分割后的日志文件
    copytruncate
    notifempty # 当日志文件为空时不分割
    missingok
    dateext  # 切割后的文件添加日期作为后缀
}

这样配置了以后系统会在凌晨3点多执行分割操作,执行结果会保存到/var/spool/mail/root中

Nginx利用Logrotate实现日志分割

查看结果发现提示权限不够而分割失败,这是因为开启了selinux导致,解决方案有如下2种:

1、关闭selinux/2、利用semanage修改待分割的日志文件所在目录的权限

# 开放/opt/logtest目录的权限
semanage fcontext -a -t var_log_t "/opt/logtest(/.*)?"
restorecon -Rv /opt/logtest

总结

到此这篇关于Nginx利用Logrotate日志分割的文章就介绍到这了!


Tags in this post...

Servers 相关文章推荐
Nginx 502 Bad Gateway错误原因及解决方案
Mar 31 Servers
Nginx location 和 proxy_pass路径配置问题小结
Sep 04 Servers
nginx安装以及配置的详细过程记录
Sep 15 Servers
OpenStack虚拟机快照和增量备份实现方法
Apr 04 Servers
基于Apache Hudi在Google云构建数据湖平台的思路详解
Apr 07 Servers
openstack云计算keystone组件工作介绍
Apr 20 Servers
Windows Server 2012 R2 磁盘分区教程
Apr 29 Servers
阿里云国际版 使用Nginx作为HTTPS转发代理服务器
May 11 Servers
讨论nginx location 顺序问题
May 30 Servers
解决Vmware虚拟机安装centos8报错“Section %Packages Does Not End With %End. Pane Is Dead”
Jun 01 Servers
Docker与K8s关系介绍不会Docker也可以使用K8s
Jun 25 Servers
Linux中sftp常用命令整理
Jun 28 Servers
nginx lua 操作 mysql
May 15 #Servers
Nginx HTTP跳转至HTTPS
Nginx 匹配方式
May 15 #Servers
nginx实现多geoserver服务的负载均衡
May 15 #Servers
Nginx 常用配置
鲲鹏 CentOS 7 安装Python3.7
May 11 #Servers
在容器中使用nginx搭建上传下载服务器
May 11 #Servers
You might like
PHP实现二维数组根据key进行排序的方法
2016/12/30 PHP
thinkphp 字母函数详解T/I/N/D/M/A/R/U
2017/04/03 PHP
javascript获取重复次数最多的字符
2015/07/08 Javascript
jQuery实现的简单提示信息插件
2015/12/08 Javascript
在ASP.NET MVC项目中使用RequireJS库的用法示例
2016/02/15 Javascript
AngularJS入门(用ng-repeat指令实现循环输出
2016/05/05 Javascript
相册展示PhotoSwipe.js插件实现
2016/08/25 Javascript
基于JS组件实现拖动滑块验证功能(代码分享)
2016/11/18 Javascript
bootstrap 表单验证使用方法
2017/01/11 Javascript
NodeJS测试框架mocha入门教程
2017/03/28 NodeJs
Node.js环境下Koa2添加travis ci持续集成工具的方法
2017/06/19 Javascript
node跨域请求方法小结
2017/08/25 Javascript
vue-cli 引入jQuery,Bootstrap,popper的方法
2018/09/03 jQuery
微信小程序module.exports模块化操作实例浅析
2018/12/20 Javascript
基于js Canvas实现二次贝塞尔曲线
2018/12/25 Javascript
Vue 样式绑定的实现方法
2019/01/15 Javascript
React通过redux-persist持久化数据存储的方法示例
2019/02/14 Javascript
如何进行微信公众号开发的本地调试的方法
2019/06/16 Javascript
使用 UniApp 实现小程序的微信登录功能
2020/06/09 Javascript
基于javascript原生判断DOM是否加载完毕
2020/10/14 Javascript
python开发之str.format()用法实例分析
2016/02/22 Python
Django项目创建到启动详解(最全最详细)
2019/09/07 Python
Python常用类型转换实现代码实例
2020/07/28 Python
Python调用SMTP服务自动发送Email的实现步骤
2021/02/07 Python
html5触摸事件判断滑动方向的实现
2018/06/05 HTML / CSS
HTML5 video 视频标签使用介绍
2014/02/03 HTML / CSS
恶意软件的定义
2014/11/12 面试题
简单说下OSPF的操作过程
2014/08/13 面试题
写clone()方法时,通常都有一行代码,是什么?
2012/10/31 面试题
计算机专业自我鉴定
2013/10/15 职场文书
中学生差生评语
2014/01/30 职场文书
美国探亲签证邀请信
2014/02/05 职场文书
党员2014两会学习心得体会
2014/03/17 职场文书
机关单位动员会主持词
2014/03/20 职场文书
《蜜蜂引路》教学反思
2016/02/22 职场文书
一定要知道的 25 个 Vue 技巧
2021/11/02 Vue.js