显而易见的做法是 tail -f app.log db.log,但生产环境有个坑:当 logrotate 轮转文件时,它会重命名文件并创建新文件,-f 保持旧的文件描述符打开,你会盯着一个冻结的屏幕。解决方案只需要改一个字符:-F 按文件名重新打开文件,而不是按 inode。下面是何时使用各种变体。
1. 显示两个文件并用文件头分隔
$ clai 同时显示这两个日志→ tail -n +1 app.log db.log==> app.log <==line A1==> db.log <==line B1
查看多个文件时,tail 会自动打印类似 ==> 文件名 <== 的文件头来显示每一行的来源。这很关键:没有文件头,你就不知道每行来自哪个日志。
2. 实时跟踪两个日志
$ clai 当新行写入时跟踪两个日志→ tail -f app.log db.log
每次来源切换时文件头会重新打印。当一个文件被写入时,看不到文件头;当另一个文件收到一行时,文件头就会出现。
3. 熬过日志轮转并继续读取
$ clai 跟踪日志不让它在轮转后沉默→ tail -F /var/log/app/app.log
这就是这篇文章的关键。-f 保持文件描述符打开:logrotate 重命名文件并创建新文件后,tail -f 会继续读取重命名后的副本,永远看不到新行。-F 监视文件名并重新打开文件。生产环境中总是用 -F。
4. 用源文件名标记每一行
$ clai 显示两个日志混在一起,但每行标记文件名→ for f in app.log db.log; do tail -F "$f" | sed "s/^/[$f] /" & done; wait
当日志同时写入时,块状文件头会很不方便。每行加个前缀更容易阅读。& 在后台启动每个 tail,wait 保持 shell 运行。
5. 监视目录中的所有日志文件,包括之后创建的
$ clai 跟踪目录中的所有日志文件→ tail -F /var/log/app/*.log
Shell 在启动时只会展开通配符一次。之后创建的文件不会被包含:需要重新启动命令。
6. 当需要带面板的真实界面时
$ clai 在单独的面板中显示多个日志→ multitail /var/log/syslog /var/log/auth.log
multitail 绘制带语法高亮和过滤器的面板。对于有四个日志的事件分类,这明显比单个流更好。需要单独安装。
常见坑
-f和-F只在轮转时不同。 轮转发生前没有区别,所以使用-f的习惯不会被处罚。只有当你在事件期间等待日志行而它停止到达时才会被处罚。tail -f在网络上不好用。 在 NFS 上,更改可能无法到达客户端。在写日志的那台机器上看日志。- 行可能会混乱。 两个写入同一流的进程没有同步。要理解事件顺序,读行内的时间戳,而不是输出顺序。
相关问题
怎样从某一特定行开始读取而不是从尾部开始? tail -n +100 file 从第 100 行开始,tail -c +1000 从第 1000 字节开始。
怎样边跟踪日志边过滤? tail -F app.log | grep --line-buffered ERROR。不加 --line-buffered,grep 会缓冲输出,行会延迟显示。
为什么 journalctl 对服务比 tail 更好? 它了解轮转,可以按单元和日志级别过滤,并且不依赖于服务写入的位置。
相关阅读
- Read a service's logs with journalctl
- Sweep old logs and backups with one sentence
- Grep with exclusions
别再死记 tail 和 logrotate 的边界情况了 —— 描述你需要看什么,CliAI 帮你写命令。一行命令安装。