# 日志
# journalctl
$ journalctl # 显示系统日志(默认显示全部日志)
-f # 跟踪日志的末尾并保持显示
-u ssh # 只显示某个 unit 的日志
-b # 只显示本次开机以来的日志
-b -1 # 只显示上一次开机的日志(取值为+1 则表示正数第 1 次开机)
--since "2019-08-12 17:00:00" # 只显示从某个时间点开始的日志
--until "2019-08-14 00:00:00"
--since "1 hour ago"
--until "10 min ago"
--disk-usage # 显示日志占用的磁盘空间
--vacuum-time=1months # 清理日志,只保留最近一段时间的
- 其日志保存在
/var/log/journal/
或/run/log/journal/
目录下。
# systemd-analyze
$ systemd-analyze # 显示系统启动的耗时
blame # 分别显示系统启动时各个进程的耗时
# logrotate
:一个 Linux 自带的命令行工具,用于定期轮换(rotate)日志文件。
- 官方文档 (opens new window)
- 假设一个程序不断生成日志到一个日志文件,导致文件体积越来越大,不方便查看和搜索,甚至可能占满磁盘。
- 为了解决该问题,通常将历史每天的日志分别保存到一个归档(archive)文件,与新产生的日志位于不同文件。该过程称为日志轮换、日志切割。
# 配置
logrotate 默认采用 /etc/logrotate.conf
作为主配置文件(用于保存 logrotate 本身的配置),还会导入 /etc/logrotate.d/
目录下的其它配置文件(用于保存各个日志轮换任务的配置)。
这些配置文件不限制扩展名,采用 logrotate 自定的语法。
用 # 声明单行注释,但必须独占一行。
例:编写一个配置文件
/etc/logrotate.d/nginx
,用于轮换 Nginx 的日志文件/usr/local/nginx/logs/*.log { # 待轮换的日志文件的绝对路径。如果有多个路径,则用空格分隔 su nginx nginx # 切换到指定的用户、用户组来执行轮换任务 # create 644 nginx nginx # 以指定权限创建新的日志文件 # 判断是否轮换: daily # 每天检查一次日志文件(还可设置 weekly、monthly、yearly),如果需要轮换,则生成一个归档日志文件 rotate 5 # 最多保留 5 个归档文件,超过该数量则删掉最旧的归档文件 missingok # 忽略日志文件不存在时的报错 notifempty # 如果日志文件为空,则不轮换 # size 10k # 如果日志文件低于指定大小,则不轮换 # 保存归档文件: # olddir old_logs # 将归档文件放到指定目录下(默认放在源目录下),可以使用相对路径或绝对路径 dateext # 创建归档文件时,加上 dateformat 字符串作为文件名后缀。归档文件名示例: error-2019-12-23-1577083161.log dateformat -%Y-%m-%d-%s # 日期字符串的格式 extension .log # 归档文件的扩展名,会放在 dateext 之后 # compress # 启用 gzip 压缩归档文件。此时文件的扩展名为 .gz # delaycompress # 每次轮换生成的归档文件,会等到下一次轮换时才压缩 # copytruncate postrotate # 每次轮换之后,执行 postrotate 与 endscript 之间的命令 if [ -f /var/run/nginx.pid ]; then /bin/kill -USR1 `cat /var/run/nginx.pid` fi endscript }
# 轮换方式
假设让 logrotate 定期轮换一次 Nginx 的日志文件 error.log ,有两种轮换方式:
- 使用 postrotate 指令
- 原理:将 error.log 重命名为归档文件 error-xx.log ,然后创建一个新的 error.log 文件,供程序继续写入日志。
- 缺点:轮换之后,日志文件的 inode 变化,因此需要重启一次程序,让程序重新根据文件路径打开该日志文件,否则程序还会将日志写入旧 inode 文件。
- Nginx 支持发送 -USR1 信号,通知程序在不重启的情况下重新打开日志文件。
- 使用 copytruncate 指令
- 原理:先创建一个归档文件 error-xx.log ,然后将 error.log 的内容拷贝到 error-xx.log 中,然后将 error.log 文件的长度截断为 0 ,供程序继续写入日志。
- 优点:轮换之后,日志文件的 inode 不变,因此不必重启程序。
- 缺点:在拷贝完成之后、截断之前,如果程序写入新的日志,则会因为截断而丢失。
- 程序调用 open() 函数打开日志文件时,应该采用 O_APPEND 追加模式。否则,当文件长度被截断为 0 时,程序会依然从之前的偏移量处继续写入数据,而偏移量之前的位置用空字节填充,导致文件变成稀疏文件。
# 启动
- logrotate 安装之后不需要保持运行,它会被 crond 每天以 root 权限启动一次,启动之后会根据配置文件执行一次日志轮换。
- 也可以添加 crontab 任务,每小时执行一次 logrotate 。
- 可以手动执行一次 logrotate ,测试一下效果:
logrotate <configfile> # 启动 logrotate 并读取某个配置文件 -d # 开启调试模式,此时不会影响实际的日志文件 -f # 主动执行一次日志轮换,不过 logrotate 可能认为此时不需要进行日志轮换
# 示例
- 创建一个日志文件:
[root@CentOS ~]# echo Hello > test.log [root@CentOS ~]# ll -rw-r--r--. 1 root root 6 Jan 12 13:45 test.log
- 轮换一次:
[root@CentOS ~]# logrotate /etc/logrotate.d/test -f [root@CentOS ~]# ll -rw-r--r--. 1 root root 6 Jan 12 13:46 test-2020-01-12.log # 轮换成功,这里归档文件的日期字符串格式为 dateformat -%Y-%m-%d -rw-r--r--. 1 root root 0 Jan 12 13:46 test.log # 原日志文件的内容变为空
- 再轮换一次:
[root@CentOS ~]# echo Hello > test.log # 使原日志文件不为空 [root@CentOS ~]# logrotate /etc/logrotate.d/test -f [root@CentOS ~]# ll -rw-r--r--. 1 root root 6 Jan 12 13:51 test-2020-01-12-2020-01-12.log -rw-r--r--. 1 root root 0 Jan 12 13:46 test-2020-01-12.log -rw-r--r--. 1 root root 6 Jan 12 13:51 test.log
- test.log 的内容不为空,但并没有轮换。因为存在一个名为 test-2020-01-12.log 的归档文件,导致 logrotate 认为已经轮换过了。除非按
dateformat -%Y-%m-%d-%s
的格式生成归档文件。 - 此时归档文件 test-2020-01-12.log 也被轮换了。为了避免循环轮换,建议在 logrotate 配置中取消使用文件名通配符,或者使用其它目录作为 olddir 。
- test.log 的内容不为空,但并没有轮换。因为存在一个名为 test-2020-01-12.log 的归档文件,导致 logrotate 认为已经轮换过了。除非按
# 日志清理方案
应用程序产生的日志文件需要定时清理,否则会占用越来越多的磁盘空间。主要分为以下几种情况:
- 程序只产生一个日志文件。此时可采用 logrotate 定期轮换、自动删除。
- 程序只产生一个日志文件,且不需要保存。此时可添加 crontab 任务,定期截断:
0 1 * * * truncate -s 1G /data/*.log
- 程序自己会每天轮换日志,并删除多天以前的日志。此时已满足要求,不需要额外操作。
- 程序自己会每天轮换日志,但不会删除多天以前的日志。此时可添加 crontab 任务,定期删除:
0 1 * * * find /data/ -name '*.log' -mtime +7 | xargs rm -f # 删除超过 7 天未修改的日志文件