从我的服务中更快地获取 systemd 服务日志

ada*_*czi 5 logs systemd journalctl systemd-journald

我有一个 systemd 服务定义如下,它工作正常:

[Unit]
Description=my service
After=network.target

[Service]
User=myuser
Group=mygroup
WorkingDirectory=/home/myuser/myapp
Environment="PATH=/home/myuser/myapp/.venv/bin"
ExecStart=/home/myuser/myapp/.venv/bin/python3 /home/myuser/myapp/run.py
Restart=on-failure

[Install]
WantedBy=multi-user.target
Run Code Online (Sandbox Code Playgroud)

这是一个基于 Flask 框架的 Python Web 应用程序。通常在应用程序的标准输出中,我可以看到传入的请求“实时”,我的意思是当我像python run.py.

现在启动服务后,我想跟踪应用程序的日志,我这样做:

sudo journalctl -f -u my_app.service
Run Code Online (Sandbox Code Playgroud)

并且传入的日志非常慢 - 有时它们需要几分钟或更长时间才能出现在日志中。之后它们都有适当的时间戳,所以它们并不是消失了,它们确实消失了,而是经过了很长时间。

我试过的:

  • 将 systemd 服务输出重定向到文件:

    StandardOutput=file:/var/log/my_app/output.log

    StandardError=file:/var/log/my_app/error.log

    运气不好 - 他们保存得很好,但速度一样慢

  • 尝试将 journalctl 日志转储到离线更快的设置SyncIntervalSec从默认5m5s- 也没有帮助

有什么方法可以更快地将这些日志从我的应用程序传递到 journald?我在使用其他服务(例如系统身份验证服务)时没有问题 - 我可以立即看到记录。我的journald.conf文件有默认参数(除了上面的一个),我的 systemd 是版本 237,我运行的是 Ubuntu 18.04。

fil*_*den 8

问题实际上是来自 Flask 应用程序的缓冲,而不是 systemd 或 journald 如何摄取这些日志。

这可能是违反直觉的,因为正如您所提到的,python3 run.py直接在命令行上运行可以正常工作并正确显示日志,并且日志上的时间戳看起来也正确。

前者发生是因为 Unix/Linux 通常会在连接到终端时将 stdout 设置为无缓冲(因为它期望与用户交互),但在连接到文件(在 的情况下StandardOutput=file:...)或管道(如果你'正在登录日志,这是默认设置。)

后者是因为 Python/Flask 记录器正在添加时间戳,所以即使它正在缓冲该输出,当它最终将其发布到日志中时,所有时间戳都在那里。

某些应用程序会知道这通常是一个问题,并且会在将 stdout 用于日志时适当地在 stdout 上设置缓冲,但是对于您正在使用的此特定 Python/Flask 设置,情况似乎并非如此。

在 Python 上,将 stdout 全局更改为无缓冲模式相当容易,您可以通过以下方式进行:

  1. 传递一个-u标志python3在你的命令。
  2. PYTHONUNBUFFERED=1在您的环境中设置(您可以在 systemd 服务单元中使用附加Environment=PYTHONUNBUFFERED=1行进行设置。)

您确认这适用于您的特定情况,太好了!

对于遇到类似问题的非 Python 应用程序,有诸如unbuffer和 之类的命令行工具stdbuf通常可以解决同样的问题。

解决方案通常特定于应用程序类型,这有点不幸,但经常在 Stack Exchange 中使用谷歌搜索或寻找其他答案(一旦您知道缓冲是问题所在)通常会给您带来有用的建议。