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

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

我的 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

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

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

sudo journalctl -f -u my_app.service

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

我尝试过的:

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

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

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

    运气不好 - 他们节省得很好,但速度同样慢

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

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

答案1

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

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

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

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

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

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

  1. 通过一个-u旗帜python3你的指挥下。
  2. 环境PYTHONUNBUFFERED=1在您的环境中(您可以在 systemd 服务单元中使用附加Environment=PYTHONUNBUFFERED=1行执行此操作。)

您确认这适用于您的具体案例,所以太好了!

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

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

相关内容