Systemd

從我的服務中更快地獲取 systemd 服務日誌

  • July 3, 2019

我有一個如下定義的 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。

問題實際上是來自 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 中搜尋或尋找其他答案(一旦您知道緩衝是問題所在)通常會為您提供有用的建議。

引用自:https://unix.stackexchange.com/questions/505146