Linux日志切割神器logrotate原理介绍和配置详解

前言

在Linux环境中能够帮助我们分析问题蛛丝马迹的有效办法之一便是日志,常见的如操作系统syslog日志/var/log/syslog,应用程序Nginx日志/var/log/nginx/*.log。但如果服务器数量较多,日志文件大小增长较快,不断消耗磁盘空间就会触发告警,如果需要人为定期按照各种维度去手动清理日志就显得十分棘手。为了节省空间和方便整理,可以将日志文件按时间或大小分成多份,删除时间久远的日志文件,这就是通常说的日志滚动(log rotation)。logrotate(GitHub地址) 诞生于 1996/11/19 是一个Linux系统日志的管理工具,本文会详细介绍Linux日志切割神器logrotate的原理和配置。
logrotate 是一个 linux 系统日志的管理工具。可以对单个日志文件或者某个目录下的文件按时间 / 大小进行切割,压缩操作;指定日志保存数量;还可以在切割之后运行自定义命令。
logrotate 是基于 crontab 运行的(准确来说是基于timer和crontab定时机制),所以这个时间点是由 crontab 控制的,具体可以查询 crontab 的配置文件 /etc/anacrontab。 系统会按照计划的频率运行 logrotate,通常是每天。在大多数的 Linux 发行版本上,计划每天运行的脚本位于 /etc/cron.daily/logrotate。
主流 Linux 发行版上都默认安装有 logrotate 包,如果你的 linux 系统中找不到 logrotate, 可以使用 apt-get 或 yum 命令来安装。

logrotate运行机制

logrotate 在很多 Linux 发行版上都是默认安装的。系统会定时运行 logrotate,一般是每天一次。系统是这么实现按天执行的。crontab 会每天定时执行 /etc/cron.daily 目录下的脚本,而这个目录下有个文件叫 logrotate。在 ubuntu 上脚本内容是这样的:

方式1 contab模式

1)检查Cron服务的状态:

systemctl status cron.service

2)检查执行Logrotate的定时任务

#cat /etc/crontab 

17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6   * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )

定时任务不执行一般问题都出现在后面的命令,所以检查一下,手动执行“test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )”,看是否报错。

3)检查定时任务下logrotate脚本

cron task:/etc/cron.daily/logrotate,每天运行一次logrotate脚本

#!/bin/sh
 
# skip in favour of systemd timer
# 如果systemd存在的话,就使用systemd timer启动,不再使用cron.daily拉起logrotate
if [ -d /run/systemd/system ]; then
    exit 0
fi

# this cronjob persists removals (but not purges)
if [ ! -x /usr/sbin/logrotate ]; then
    exit 0
fi
#  执行logrotate应用,其配置文件为/etc/logrotate.conf
/usr/sbin/logrotate /etc/logrotate.conf
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
    /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit $EXITVALUE

再来看一下/etc/logrotate.conf配置文件内容:

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

# use the adm group by default, since this is the owning group
# of /var/log/syslog.
su root adm

# 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

# packages drop log rotation information into this directory
# /var/log下每种日志的具体配置,可以看/etc/logrotate.d/ 目录下配置文件的具体配置
include /etc/logrotate.d

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

比如syslog的配置在/etc/logrotate.d/rsyslog中:

/var/log/syslog
{
    su root root
	rotate 7
	daily
	missingok
	notifempty
	delaycompress
	compress
	postrotate
		/usr/lib/rsyslog/rsyslog-rotate
	endscript
}

/var/log/mail.info
/var/log/mail.warn
/var/log/mail.err
/var/log/mail.log
/var/log/daemon.log
/var/log/kern.log
/var/log/auth.log
/var/log/user.log
/var/log/lpr.log
/var/log/cron.log
/var/log/debug
/var/log/messages
{
   su root root
	rotate 4
	weekly
	missingok
	notifempty
	compress
	delaycompress
	sharedscripts
	postrotate
		/usr/lib/rsyslog/rsyslog-rotate
	endscript
}

4)检查logrotate服务的状态

#systemctl status logrotate.service

● logrotate.service - Rotate log files
     Loaded: loaded (/lib/systemd/system/logrotate.service; static; vendor preset: enabled)
     Active: failed (Result: exit-code) since Wed 2021-12-08 00:00:03 +08; 16h ago
TriggeredBy: ● logrotate.timer
       Docs: man:logrotate(8)
             man:logrotate.conf(5)
   Main PID: 2811680 (code=exited, status=1/FAILURE)

Dec 08 00:00:01 systemd[1]: Starting Rotate log files...
Dec 08 00:00:03 logrotate[2811680]: error: failed to rename /usr/squid/logs/access.log to /usr/squid/logs/access.log-20211208: Read-only file system

这里通过TriggeredBy:logrotate.timer可以发现logrotate确实是通过Systemd timer的方式来做定时任务的。

方式2 Systemd模式

使用Systemd timer模式主要是两个服务,一个是logrotate.service,logrotate.timer

1)查看logrotate.service的状态

#systemctl status logrotate.service

● logrotate.service - Rotate log files
     Loaded: loaded (/lib/systemd/system/logrotate.service; static; vendor preset: enabled)
     Active: failed (Result: exit-code) since Wed 2021-12-08 00:00:03 +08; 16h ago
TriggeredBy: ● logrotate.timer
       Docs: man:logrotate(8)
             man:logrotate.conf(5)
   Main PID: 2811680 (code=exited, status=1/FAILURE)

Dec 08 00:00:01 systemd[1]: Starting Rotate log files...
Dec 08 00:00:03 logrotate[2811680]: error: failed to rename /usr/squid/logs/access.log to /usr/squid/logs/access.log-20211208: Read-only file system

TriggeredBy: logrotate.timer;这里可以知道这个服务是由logrotate.timer触发执行的;这里有Read-only file system的报错,主要是Systemd的logrotate.service文件中,对logrotate加了文件读写保护,当 ProtectSystem=full这个参数时,会把 /usr/, /boot, /efi, /etc 挂载为只读,如果是 ProtectSystem=strict 那么整个文件系统都会挂载为只读。刚好我的日志目录就在/usr/下,因此需要再加一个参数:ReadWritePaths=/usr/squid/logs即可,然后systemctl daemon-reload && systemctl restart logrotate.service。这里需要思考的问题是日志目录设置在/usr/下是否合理?

[Unit]
Description=Rotate log files
Documentation=man:logrotate(8) man:logrotate.conf(5)
ConditionACPower=true

[Service]
Type=oneshot
ExecStart=/usr/sbin/logrotate /etc/logrotate.conf

# performance options
Nice=19
IOSchedulingClass=best-effort
IOSchedulingPriority=7

# hardening options
#  details: https://www.freedesktop.org/software/systemd/man/systemd.exec.html
#  no ProtectHome for userdir logs
#  no PrivateNetwork for mail deliviery
#  no ProtectKernelTunables for working SELinux with systemd older than 235
#  no MemoryDenyWriteExecute for gzip on i686
PrivateDevices=true
PrivateTmp=true
ProtectControlGroups=true
ProtectKernelModules=true
ProtectSystem=full
RestrictRealtime=true
ReadWritePaths=/usr/squid/logs

2)检查logrotate.timer的状态

# systemctl status logrotate.timer   
● logrotate.timer - Daily rotation of log files
     Loaded: loaded (/lib/systemd/system/logrotate.timer; enabled; vendor preset: enabled)
     Active: active (waiting) since Thu 2021-08-05 11:08:00 +08; 4 months 3 days ago
    Trigger: Thu 2021-12-09 00:00:00 +08; 7h left
   Triggers: ● logrotate.service
       Docs: man:logrotate(8)
             man:logrotate.conf(5)

Trigger:可以看出他的触发时间
Triggers:可以看出他将触发的服务

查看logrotate.timer的配置

[Unit]
Description=Daily rotation of log files
Documentation=man:logrotate(8) man:logrotate.conf(5)

[Timer]
OnCalendar=daily
AccuracySec=12h
Persistent=true
#Unit:真正要执行的任务,默认是同名的带有.service后缀的单元

[Install]
WantedBy=timers.target

3)检查logrotate脚本
使用logrotate切割的脚本一般都放在/etc/logrotate.d/ 下,因此我的squid切割也在这个目录下,可以通过logrotate -d /etc/logrotate.d/squid 检测一下,-d表示debug模式;在这里debug时候发现logrotate有一个status状态文件/var/lib/logrotate/status,也就是记录下文件logrotate的时间,在今天有做过rotate的话,那么就不会再一次进行,如果想要测试,可以编辑这个文件你想要测试的文件的时间,比如发现里面有一条日志:“/usr/squid/logs/access.log” 2021-12-9-14:33:28 说明今天做了切割了,还想做测试则可以改为:“/usr/squid/logs/access.log” 2021-12-7-14:33:28,那么就可以再一次测试了。注意:这个status的状态只能改时间,直接删除这一条是不生效的。

4)验证

systemctl restart logrotate.service

重新执行systemctl restart logrotate.service后,就可以看到被切割的日志;如:access.log-20211209等

logrotate原理

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

Linux 文件操作机制

介绍一下相关的 Linux 下的文件操作机制。
Linux 文件系统里文件和文件名的关系如下图。
在这里插入图片描述
目录也是文件,文件里存着文件名和对应的 inode 编号。通过这个 inode 编号可以查到文件的元数据和文件内容。文件的元数据有引用计数、操作权限、拥有者 ID、创建时间、最后修改时间等等。文件件名并不在元数据里而是在目录文件中。因此文件改名、移动,都不会修改文件,而是修改目录文件。
借《UNIX 环境高级编程》里的图说一下进程打开文件的机制。

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

create

这也就是默认的方案,可以通过 create 命令配置文件的权限和属组设置;这个方案的思路是重命名原日志文件,创建新的日志文件。详细步骤如下:

1、重命名正在输出日志文件,因为重命名只修改目录以及文件的名称,而进程操作文件使用的是 inode,所以并不影响原程序继续输出日志。
2、创建新的日志文件,文件名和原日志文件一样,注意,此时只是文件名称一样,而 inode 编号不同,原程序输出的日志还是往原日志文件输出。
3、最后通过某些方式通知程序,重新打开日志文件;由于重新打开日志文件会用到文件路径而非 inode 编号,所以打开的是新的日志文件。
如上也就是 logrotate 的默认操作方式,也就是 mv+create 执行完之后,通知应用重新在新文件写入即可。mv+create 成本都比较低,几乎是原子操作,如果应用支持重新打开日志文件,如 syslog, nginx, mysql 等,那么这是最好的方式。

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

copytruncate

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

1、将当前正在输出的日志文件复制为目标文件,此时程序仍然将日志输出到原来文件中,此时,原文件名也没有变。
2、清空日志文件,原程序仍然还是输出到预案日志文件中,因为清空文件只把文件的内容删除了,而 inode 并没改变,后续日志的输出仍然写入该文件中。
如上所述,对于 copytruncate 也就是先复制一份文件,然后清空原有文件。
通常来说,清空操作比较快,但是如果日志文件太大,那么复制就会比较耗时,从而可能导致部分日志丢失。不过这种方式不需要应用程序的支持即可。

运行logrotate

具体 logrotate 命令格式如下:

logrotate [OPTION...] <configfile>
-d, --debug :debug 模式,测试配置文件是否有错误。
-f, --force :强制转储文件。
-m, --mail=command :压缩日志后,发送日志到指定邮箱。
-s, --state=statefile :使用指定的状态文件。
-v, --verbose :显示转储过程。

通常惯用的做法是配合 crontab 来定时调用。

crontab -e
# 每30分钟执行一次logrotate
*/30 * * * * /usr/sbin/logrotate /etc/logrotate.d/rsyslog > /dev/null 2>&1 &
# 或者
*/30 * * * * /usr/sbin/logrotate /etc/logrotate.conf > /dev/null 2>&1 &

logrotate参数说明

参数说明
daily
weekly
monthly
yearly
切割周期,多久切割一次。
daily : 切割周期为 每天
weekly : 切割周期为 每周
monthly : 切割周期为 每月
yearly: 切割周期为 每年
size size当日志文件到达指定的大小时才转储。
默认单位是 bytes。bytes (缺省) 及 KB (sizek) 或 MB (sizem)
如: size 30k、 size 50M
rotate count日志文件保留备份的个数。默认是 0
如:0 指没有备份;5 指保留最近的5个备份,其余的全部删除。
maxage count保留多少天的日志文件。
如:5 指保留最近的5天的日志文件,其余的全部删除。
如果 日志文件按天转储,则 rotatemaxage 基本上是一样的。
tabooext [+] list让 logrotate 不转储指定扩展名的文件,缺省的扩展名是:.rpm-orig, .rpmsave, v, 和~
missingokmissing ok ,在日志轮循期间,错误将被忽略。
例如 “文件无法找到” 之类的错误。
copytruncate
nocopytruncate
copytruncate: 用于还在打开中的日志文件,把当前日志备份并截断。 把正在输出的日志拷 (copy) 一份出来,再清空 (trucate) 原来的日志。
nocopytruncate: 备份日志文件,但是不截断 。
create mode owner group
nocreate
create mode owner group:转储文件,使用指定的文件模式创建新的日志文件。
nocreate: 不建立新的日志文件。
如: create 644 root root
以指定的权限创建全新的日志文件,同时 logrotate 也会重命名原始日志文件。
nocompress
compress
nocompress: 不压缩(默认)
compress: 通过 gzip 压缩转储以后的日志。如 XXX.gz
delaycompress
nodelaycompress
delaycompress: 和 compress 一起使用时,转储的日志文件到下一次转储时才压缩。
nodelaycompress: 覆盖 delaycompress 选项,转储同时压缩。
prerotate
endscript
在所有其它指令完成 执行。这两个关键字必须单独成行
postrotate
endscript
在所有其它指令完成 执行。这两个关键字必须单独成行
sharedscripts共享脚本,整个日志组运行一次脚本 。
比如 nginx 涉及到多个日志文件,一般使用 * 号 通配符:/var/log/nginx/*.log { ... }
sharedscripts 的作用是在 所有的日志文件 都轮转完毕后 统一执行一次脚本
如果没有 sharedscripts ,那么 每个日志文件 轮转完毕后 都会执行一次脚本
errors address转储时的错误信息发送到指定的 Email 地址。
mail address
nomail
mail address : 把转储的日志文件发送到指定的 E-mail 地址
nomail : (默认)转储时不发送日志文件
ifempty
notifempty
ifempty :if empty ,即使是空文件也转储(默认)。
notifempty :not if empty ,如果是空文件的话,不转储。
olddir directory
noolddir
olddir directory :储后的日志文件放入指定的目录,必须和当前日志文件在同一个文件系统。
noolddir : 转储后的日志文件和当前日志文件放在同一个目录下。
dateext在日志名称后面,添加日期后缀。默认是当前日期。默认是 -%Y%m%d 的后缀。
可用 dateformat 选项扩展配置。
如:nginx_access.log --> nginx_access.log-20210120
注意: 格式化日期中不要出现 分号(:) ,因为文件名称是不能含有分号的。
dateformatdateext 的拓展,必须配合 dateext 使用
在V3.9.0 之前,只支持 %Y%m%d%s 参数。
%s 不是秒,是时间戳,也者 随机数,具体我没有验证。
在V3.9.0 及之后,支持 %H 参数。
如: dateformat -%Y-%m-%d
结果:nginx_access.log --> nginx_access.log-2021-01-20
注意: 文件名称中禁止出现分号(:) ,因为文件名称是不能含有分号的。
dateyesterdaydateext 配合使用,日期提前一天。
比如,当前日期是2021-01-20,提前一天就是 2021-01-19
extensiondateextdateformat 配合使用,指定文件的后缀。
如:extension .log
结果:nginx_access.log --> nginx_access-2021-01-20.log
说明:nginx_access.log , 文件名是nginx_access,后缀是.log, 文件名 + -%Y-%m-%d 格式的日期 + .log 后缀,结果是 nginx_access-2021-01-20.log

本文参考连接

https://blog.csdn.net/xiaojin21cen/article/details/122309230
https://zhuanlan.zhihu.com/p/90507023
https://zhuanlan.zhihu.com/p/444111643

### Logrotate Configuration Overview In Linux systems, `logrotate` plays an essential role in managing logs efficiently. Two primary configuration aspects exist within the context of log management: `/etc/logrotate.conf` and files located inside the directory `/etc/logrotate.d/`. Each serves distinct purposes yet collaborates seamlessly to ensure effective handling of system logging. #### Understanding /etc/logrotate.conf The file `/etc/logrotate.conf` acts as the global configuration for all log rotation activities on a machine. This central location defines default settings applicable across various services unless overridden locally. Common parameters include specifying where rotated logs are stored, defining frequency (daily, weekly, monthly), setting up compression options, controlling retention policies through count limits, and more[^1]. For instance: ```bash # Sample content from /etc/logrotate.conf weekly rotate 4 compress delaycompress notifempty create 0644 root adm include /etc/logrotate.d ``` This excerpt sets rotations every week (`weekly`) while keeping four old versions (`rotate 4`). Compression occurs after one cycle due to `delaycompress`, ensuring current archives remain uncompressed until their next scheduled turn. Logs empty during inspection won't trigger unnecessary processing thanks to `notifempty`. #### Exploring /etc/logrotate.d/ Conversely, individual service-specific configurations reside under directories like `/etc/logrotate.d/`. These separate entries allow granular control over particular applications without modifying core directives set globally via `logrotate.conf`. Developers or administrators add custom rules here tailored specifically towards unique requirements per application or daemon involved. An example entry might look similar to below when targeting Apache HTTP Server's access logs: ```bash # Content typically found within /etc/logrotate.d/apache2 /var/log/apache2/*.log { daily missingok rotate 14 compress delaycompress notifempty create 640 root adm } ``` Here, specific instructions apply only to web server-related records managed separately despite inheriting broader guidelines established earlier. --- --related questions-- 1. How does configuring log expiration impact disk space utilization? 2. What security benefits arise from properly rotating sensitive logs regularly? 3. Can third-party tools integrate with logrotate mechanisms effectively? 4. In what scenarios would overriding global logrotate settings become necessary? 5. Are there performance implications associated with frequent versus infrequent log rotations?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值