近期因等保需求,需要对nginx日志做轮转并保留180天的日志,服务器操作系统是Rocky Linux 9。
Linux本身是可以通过logrotate实现日志轮转的,按照以往的经验,这本是件非常简单的事情,没想到也踩了不大不小几个坑。先分别执行以下步骤:
- 修改
/etc/logrotate.conf
```see "man logrotate" for details
全局选项不影响前面的 include 指令
修改成每日轮转,原配置是每周
weekly
daily
保留180天
rotate 180
在轮转旧日志文件后创建新的(空的)日志文件
create
将日期用作轮转文件的后缀
dateext
如果你不希望日志文件被压缩,请取消这行的注释
compress
将用户的应用日志轮转信息放入此目录
include /etc/logrotate.d
特定系统日志也可以在这里配置。
- 在`/etc/logrotate.d`目录下加入nginx轮转配置文件,这里就命名为nginx。本例中nginx安装在home/mickeylan/server/nginx目录下,大家可以根据自己的实际环境设置。
/home/mickeylan/server/nginx/logs/*log {
create 0644 root root
daily
rotate 180
dateext
missingok
notifempty
compress
sharedscripts
postrotate
/bin/kill -USR1 cat home/mickeylan/server/nginx/logs/nginx.pid 2>/dev/null 2>/dev/null || true
endscript
}
相关参数说明:
**rotate**
* `rotate 次数`: 日志文件在轮转指定次数后被移除或邮寄到 mail 指令中指定的地址。如果次数为 0,则删除旧版本而不是轮转。如果次数为 -1,则旧日志根本不会被删除,除非受到 maxage 的影响(请谨慎使用,可能会浪费性能和磁盘空间)。默认为 0。
* `olddir 目录`: 将日志移动到指定目录进行轮转。除非使用了 copy、copytruncate 或 renamecopy 选项,否则该目录必须与正在轮转的日志文件位于同一物理设备上。除非指定了绝对路径,否则该目录假定为相对于包含日志文件的目录。使用此选项时,所有旧版本的日志都会存放在该目录中。此选项可以被 noolddir 选项覆盖。
* `noolddir`: 日志在其通常所在的目录中轮转(这会覆盖 olddir 选项)。
* `su 用户 组`: 使用此用户和组来轮转日志文件,而不是使用默认的用户/组(通常是 root)。`用户` 指定用于轮转的用户,`组` 指定用于轮转的组(有关详细信息,请参阅 USER AND GROUP 部分)。如果您在此处指定的用户/组没有足够的权限来使用 create 指令中指定的所有权创建文件,将导致错误。如果 logrotate 以 root 权限运行,建议使用 su 指令来轮转由非特权用户直接或间接控制的目录中的文件。
**频率**
* `hourly`: 每小时轮转日志文件。请注意,通常 logrotate 被配置为每天由 cron 运行(或在使用 systemd(1) 时由 logrotate.timer 运行)。您必须更改此配置并每小时运行 logrotate 才能实现真正的每小时轮转。
* `daily`: 每天轮转日志文件。
* `weekly [工作日]`: 在每个工作日轮转一次日志文件,或者如果自上次轮转以来日期至少提前了 7 天(忽略具体时间)。工作日的解释如下:0 表示星期日,1 表示星期一,...,6 表示星期六;特殊值 7 表示每 7 天一次,与工作日无关。如果省略工作日参数,则默认为 0。
* `monthly`: 在月份中第一次运行 logrotate 时轮转日志文件(通常是在月份的第一天)。
* `yearly`: 如果当前年份与上次轮转的年份不同,则轮转日志文件。
* `size 大小`: 仅当日志文件增长到大于指定大小时才进行轮转。如果大小后跟 `k`,则大小以千字节为单位。如果使用 `M`,则大小以兆字节为单位,如果使用 `G`,则大小以千兆字节为单位。因此 `size 100`、`size 100k`、`size 100M` 和 `size 100G` 都是有效的。此选项与时间间隔选项互斥,并且如果它在时间条件之后指定(最后指定的选项具有优先权),它会导致日志文件轮转而不管上次轮转时间。
**文件选择**
* `missingok`: 如果日志文件缺失,继续处理下一个而不报错。另见 nomissingok。
* `nomissingok`: 如果日志文件不存在,则报错。这是默认行为。
* `ignoreduplicates`: 忽略日志文件的任何后续匹配项。
* `ifempty`: 即使日志文件为空也进行轮转,覆盖 notifempty 选项(ifempty 是默认值)。
* `notifempty`: 如果日志文件为空,则不进行轮转(这会覆盖 ifempty 选项)。
* `minage 天数`: 不轮转小于指定天数的日志。
* `maxage 天数`: 移除轮转时间超过指定天数的旧日志。仅当要轮转日志文件时才检查时间。`rotate -1` 不会阻止移除。如果配置了 maillast 和 mail,文件将被邮寄到配置的地址。
* `minsize 大小`: 当日志文件增长到大于指定大小时进行轮转,但不会在额外指定的时间间隔(daily、weekly、monthly 或 yearly)之前进行。相关的 size 选项类似,只是它与时间间隔选项互斥,并且如果它在时间条件之后指定(最后指定的选项具有优先权),它会导致日志文件轮转而不管上次轮转时间。当使用 minsize 时,会同时考虑日志文件的大小和时间戳。
* `maxsize 大小`: 当日志文件增长到大于指定大小时进行轮转,即使是在额外指定的时间间隔(daily、weekly、monthly 或 yearly)之前。相关的 size 选项类似,只是它与时间间隔选项互斥,并且如果它在时间条件之后指定(最后指定的选项具有优先权),它会导致日志文件轮转而不管上次轮转时间。当使用 maxsize 时,会同时考虑日志文件的大小和时间戳。
* `tabooext [+] 列表`: 更改当前的禁忌扩展列表(有关禁忌扩展的信息,请参见 include 指令)。如果列表前有 `+`,则扩充当前的禁忌扩展列表,否则替换它。启动时,禁忌扩展列表为:`,v, .bak, .cfsaved, .disabled, .dpkg-bak, .dpkg-del, .dpkg-dist, .dpkg-new, .dpkg-old, .dpkg-tmp, .new, .old, .orig, .rhn-cfg-tmp-*, .rpmnew, .rpmorig, .rpmsave, .swp, .ucf-dist, .ucf-new, .ucf-old, ~`。
* `taboopat [+] 列表`: 更改当前的禁忌通配符模式列表(有关禁忌扩展和模式的信息,请参见 include 指令)。如果列表前有 `+`,则扩充当前的禁忌模式列表,否则替换它。启动时,禁忌模式列表为空。
**文件和文件夹**
* `create 模式 所有者 组`, `create 所有者 组`: 在轮转后立即(在运行 postrotate 脚本之前)创建日志文件(与刚轮转的日志文件同名)。`模式` 以八进制形式指定日志文件的模式(与 chmod(2) 相同),`所有者` 指定将拥有日志文件的用户,`组` 指定日志文件所属的组(有关详细信息,请参阅 USER AND GROUP 部分)。可以省略任何日志文件属性,在这种情况下,新文件的这些属性将使用原始日志文件的相同值。可以使用 nocreate 选项禁用此选项。
* `nocreate`: 不创建新的日志文件(这会覆盖 create 选项)。
* `createolddir 模式 [所有者 [组]]`, `createolddir [所有者 [组]]`: 如果 olddir 指令指定的目录不存在,则创建它。`模式` 以八进制形式指定 olddir 目录的模式(与 chmod(2) 相同),`所有者` 指定将拥有 olddir 目录的用户,`组` 指定 olddir 目录所属的组(有关详细信息,请参阅 USER AND GROUP 部分)。如果未指定模式,则假定为 0755。可以使用 nocreateolddir 选项禁用此选项。
* `nocreateolddir`: 当 olddir 目录不存在时,不由 logrotate 创建。
* `copy`: 创建日志文件的副本,但完全不更改原始文件。例如,当需要截断或解析文件的某些其他实用程序时,或者需要创建当前日志文件的快照时,可以使用此选项。使用此选项时,create 选项将无效,因为旧日志文件保留在原处。copy 选项允许使用 olddir 指令将轮转的日志文件存储在不同的设备上。
* `nocopy`: 不复制原始日志文件,将其保留在原处(这会覆盖 copy 选项)。
* `copytruncate`: 在创建副本后,将原始日志文件就地截断为零大小,而不是移动旧日志文件并选择性地创建新文件。当某些程序无法被告知关闭其日志文件,因此可能永远继续写入(追加)到先前的日志文件时,可以使用此选项。请注意,在复制文件和截断文件之间有一个非常小的时间间隔,因此可能会丢失一些日志数据。使用此选项时,create 选项将无效,因为旧日志文件保留在原处。copytruncate 选项允许使用 olddir 指令将轮转的日志文件存储在不同的设备上。copytruncate 选项隐含 norenamecopy。
* `nocopytruncate`: 在创建副本后不就地截断原始日志文件(这会覆盖 copytruncate 选项)。
* `renamecopy`: 日志文件通过添加 ".tmp" 扩展名被重命名为同一目录中的临时文件名。之后,运行 postrotate 脚本,并将日志文件从临时文件名复制到最终文件名。最后,删除临时文件名。renamecopy 选项允许使用 olddir 指令将轮转的日志文件存储在不同的设备上。renamecopy 选项隐含 nocopytruncate。
* `norenamecopy`: 不重命名和复制原始日志文件(这会覆盖 renamecopy 选项)。
* `shred`: 使用 `shred -u` 而不是 `unlink()` 来删除日志文件。这应确保日志在其计划删除后不可读;默认情况下此选项是关闭的。另见 noshred。
* `noshred`: 删除旧日志文件时不使用 shred。另见 shred。
* `shredcycles 次数`: 要求 GNU shred(1) 在删除前覆盖日志文件指定次数。没有此选项,将使用 shred 的默认值。
* `allowhardlink`: 轮转具有多个硬链接的文件;默认情况下此选项是关闭的。目标文件可能会被清空,例如使用 shred 或 copytruncate。请谨慎使用,尤其是当日志文件以 root 身份轮转时。
* `noallowhardlink`: 不轮转具有多个硬链接的文件。另见 allowhardlink。
**压缩**
* `compress`: 旧版本的日志文件默认使用 gzip(1) 进行压缩。另见 nocompress。
* `nocompress`: 不压缩旧版本的日志文件。另见 compress。
* `compresscmd`: 指定使用哪个命令来压缩日志文件。默认为 gzip(1)。另见 compress。
* `uncompresscmd`: 指定使用哪个命令来解压缩日志文件。默认为 gunzip(1)。
* `compressext`: 如果启用了压缩,指定用于压缩日志文件的扩展名。默认遵循配置的压缩命令的扩展名。
* `compressoptions`: 可以传递命令行选项给压缩程序(如果使用的话)。对于 gzip(1),默认为 "-6"(偏向于高压缩率而牺牲速度)。如果您使用不同的压缩命令,可能需要更改 compressoptions 以匹配。
* `delaycompress`: 将上一次轮转的日志文件的压缩推迟到下一个轮转周期。仅当与 compress 结合使用时才有效。当某些程序无法被告知关闭其日志文件,因此可能会继续向先前的日志文件写入一段时间时,可以使用此选项。
* `nodelaycompress`: 不将上一次轮转的日志文件的压缩推迟到下一个轮转周期(这会覆盖 delaycompress 选项)。
**文件名**
* `extension 扩展名`: 带有指定扩展名的日志文件可以在轮转后保留它。如果使用了压缩,压缩扩展名(通常为 .gz)出现在该扩展名之后。例如,您有一个名为 mylog.foo 的日志文件,并希望将其轮转为 mylog.1.foo.gz 而不是 mylog.foo.1.gz。
* `addextension 扩展名`: 轮转后给日志文件添加最终的扩展名。如果原始文件已经以该扩展名结尾,则不会重复扩展名,而只是将其移动到末尾,即 filename 和 filenameext 都会被轮转为 filename.1ext。如果使用了压缩,压缩扩展名(通常为 .gz)出现在该扩展名之后。
* `start 起始数`: 这是用作轮转基础的编号。例如,如果指定 0,则日志在从原始日志文件轮转时将创建带有 .0 扩展名的文件。如果指定 9,则日志文件将创建带有 .9 扩展名的文件,跳过 0–8。文件仍将按照 rotate 指令指定的次数进行轮转。
* `dateext`: 使用日期扩展名(如 YYYYMMDD)来归档旧版本的日志文件,而不是简单地添加数字。可以使用 dateformat 和 dateyesterday 选项配置扩展名。
* `nodateext`: 不使用日期扩展名归档旧版本的日志文件(这会覆盖 dateext 选项)。
* `dateformat 格式字符串`: 使用类似于 strftime(3) 函数的表示法指定 dateext 的扩展名。只允许 `%Y`、`%m`、`%d`、`%H`、`%M`、`%S`、`%V`、`%s` 和 `%z` 说明符。默认值为 `-%Y%m%d`,但 hourly 除外,它使用 `-%Y%m%d%H` 作为默认值。请注意,分隔日志名称和扩展名的字符也是 dateformat 字符串的一部分。系统时钟必须设置为 2001 年 9 月 9 日之后,`%s` 才能正常工作。请注意,此格式生成的日期戳必须按字典顺序可排序(即首先是年,然后是月,然后是日。例如 2001/12/01 是可以的,但 01/12/2001 不行,因为 01/11/2002 排序会更低,而它实际上更晚)。这是因为当使用 rotate 选项时,logrotate 会对所有轮转的文件名进行排序以找出哪些日志文件更旧应该被移除。
* `dateyesterday`: 使用昨天的日期而不是今天的日期来创建 dateext 扩展名,以便轮转后的日志文件名称中的日期与其内部的时间戳相同。
* `datehourago`: 使用一小时前的日期而不是当前日期来创建 dateext 扩展名,以便轮转后的日志文件名称中的小时数与其内部的时间戳相同。与 rotate hourly 一起使用时很有用。
**邮件**
* `mail 地址`: 当日志被轮转并超出保留范围时,将其邮寄到指定地址。如果不应由特定日志生成邮件,可以使用 nomail 指令。
* `nomail`: 不将旧日志文件邮寄到任何地址。
* `mailfirst`: 使用 mail 命令时,邮寄刚刚轮转的文件,而不是即将过期的文件。
* `maillast`: 使用 mail 命令时,邮寄即将过期的文件,而不是刚刚轮转的文件(这是默认行为)。
**附加配置文件**
* `include 文件或目录`: 将作为参数给定的文件读入,就像它内联出现在 include 指令所在的位置一样。如果给定了一个目录,则在处理包含文件继续之前,按字母顺序读取该目录中的大多数文件。唯一被忽略的文件是非普通文件(如目录和命名管道)以及名称以 tabooext 或 taboopat 指令分别指定的禁忌扩展名或模式之一结尾的文件。给定的路径可以以 `~/` 开头,使其相对于执行用户的主目录。出于安全原因,配置文件不得是组可写或全局可写的。
**脚本**
* `sharedscripts`: 通常,prerotate 和 postrotate 脚本会为每个被轮转的日志运行,并且日志文件的绝对路径作为第一个参数传递给脚本。这意味着对于匹配多个文件的日志文件条目(例如 `/var/log/news/*` 示例),一个脚本可能会运行多次。如果指定了 sharedscripts,则无论有多少日志匹配通配符模式,脚本都只运行一次,并且整个模式会传递给它们。但是,如果模式中没有日志需要轮转,则根本不会运行脚本。如果脚本退出错误(或任何日志轮转失败),则不会对任何日志执行剩余的操作。此选项覆盖 nosharedscripts 选项。
* `nosharedscripts`: 为每个被轮转的日志文件运行 prerotate 和 postrotate 脚本(这是默认行为,覆盖 sharedscripts 选项)。日志文件的绝对路径作为第一个参数传递给脚本。最终轮转的日志文件的绝对路径作为第二个参数传递给 postrotate 脚本。如果脚本退出错误,则仅对受影响的日志不执行剩余的操作。
* `firstaction` <br> `脚本` <br> `endscript`: 该脚本在所有匹配通配符模式的日志文件被轮转之前、在运行 prerotate 脚本之前执行一次,并且仅当至少有一个日志实际上将被轮转时执行。这些指令只能出现在日志文件定义内部。整个模式作为第一个参数传递给脚本。如果脚本退出错误,则不进行进一步处理。另见 lastaction 和 SCRIPTS 部分。
* `lastaction` <br> `脚本` <br> `endscript`: 该脚本在所有匹配通配符模式的日志文件被轮转之后、在运行 postrotate 脚本之后执行一次,并且仅当至少有一个日志被轮转时执行。这些指令只能出现在日志文件定义内部。整个模式作为第一个参数传递给脚本。如果脚本退出错误,则仅显示错误消息(因为这是最后一个操作)。另见 firstaction 和 SCRIPTS 部分。
* `prerotate` <br> `脚本` <br> `endscript`: 该脚本在轮转日志文件及其旧日志之前执行,并且仅当日志实际上将被轮转时执行。这些指令只能出现在日志文件定义内部。通常,日志文件的绝对路径作为第一个参数传递给脚本。如果指定了 sharedscripts,则整个模式传递给脚本。另见 postrotate 和 SCRIPTS 部分。有关错误处理,请参见 sharedscripts 和 nosharedscripts。
* `postrotate` <br> `脚本` <br> `endscript`: 该脚本在日志文件被轮转之后、在日志文件被压缩之前执行。这些指令只能出现在日志文件定义内部。通常,日志文件的绝对路径作为第一个参数传递给脚本,最终轮转的日志文件的绝对路径作为第二个参数传递给脚本。如果指定了 sharedscripts,则整个模式作为第一个参数传递给脚本,第二个参数被省略。另见 prerotate 和 SCRIPTS 部分。有关错误处理,请参见 sharedscripts 和 nosharedscripts。
* `preremove` <br> `脚本` <br> `endscript`: 该脚本在即将移除日志文件之前执行一次。logrotate 将即将被移除的文件名作为第一个参数传递给脚本。另见 firstaction 和 SCRIPTS 部分。
**脚本**
起始关键字(例如 prerotate)和 `endscript`(两者都必须单独成行)之间的行将被执行(使用 `/bin/sh`)。脚本继承 logrotate 进程的一些特性,包括 stderr、stdout、当前目录、环境和 umask。脚本以调用用户和组的身份运行,无论是否有任何 su 指令。如果指定了 `--log` 标志,则文件描述符 3 是日志文件。当前工作目录未指定。
**用户和组**
用户和组标识符首先尝试通过文本表示形式解析,如果失败,则通过数字值解析。
**文件**
* `/var/lib/logrotate/logrotate.status`: 默认状态文件。
* `/etc/logrotate.conf`: 配置选项。
- 配置完成后可执行logrotate命令检查配置参数是否正确:
```bash
logrotate -f /etc/logrotate.d/nginx -v
logrotete选项说明:
选项
-f, --force: 强制 logrotate 进行轮转,即使它认为没有必要。有时在向 logrotate 配置文件添加新条目后,或者手动删除了旧日志文件时,这很有用,因为新文件将被创建,日志记录将继续正常进行。-d, --debug: 开启调试模式,这意味着不会对日志进行任何更改,也不会更新 logrotate 状态文件。只会打印调试信息。-s, --state 状态文件: 告诉 logrotate 使用替代的状态文件。如果为不同的日志文件集以不同用户身份运行 logrotate,这很有用。为防止并行执行,logrotate 默认会获取状态文件上的锁;如果无法获取锁,logrotate 将以状态码 3 退出。默认的状态文件是/var/lib/logrotate/logrotate.status。如果状态文件指定为/dev/null,则 logrotate 不会尝试锁定或写入状态文件。--skip-state-lock: 不锁定状态文件,例如在不支持锁定或禁止锁定的情况下使用。--wait-for-state-lock: 等待另一个 logrotate 进程释放对状态文件的锁。此选项可能导致 logrotate 无限期等待。请谨慎使用。-v, --verbose: 开启详细模式,例如在轮转期间显示消息。-l, --log 文件: 告诉 logrotate 将详细输出记录到指定的日志文件中。记录到该文件的详细输出与使用-v开关运行 logrotate 时相同。每次执行 logrotate 时都会覆盖该日志文件。-m, --mail 命令: 告诉 logrotate 在邮寄日志时使用哪个命令。该命令应接受以下参数:
1) 使用-s 主题给出的消息主题。
2) 收件人。
然后,该命令必须从标准输入读取消息并将其邮寄给收件人。默认的邮件命令是/bin/mail。--usage: 打印简短的使用信息。-?, --help: 打印帮助信息。--version: 显示版本信息。
本以为这样配置完就万事大吉了,以前在CentOS、ubuntu上确实也是这样做的。没想到第二天登录服务器却发现并未按照预期的那样对nginx日志做轮转操作,经过对比发现这里将轮转频率设置成了每天一次,日志轮转是通过crond触发的,于是检查/etc/cron.daily目录,发现此目录空空如也,原来如此!
在此目录下创建logrotate脚本:
#!/bin/sh
/usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
/usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit 0
然后执行chmod +x logrotate赋予执行权限。第二天再检查,发现日志正常轮转了。
此外还需注意,在Rocky Linux上不要将nginx的日志放在/usr/local一类的系统目录下,否则轮转时会报权限不足,一定要注意!!!