從我的服務中更快地獲取 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
從預設5m
到5s
- 也沒有幫助有什麼方法可以更快地將這些日誌從我的應用程序傳遞到日誌記錄?我在使用其他服務(如係統身份驗證服務)時沒有問題——我會立即看到記錄。我的
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 全域更改為無緩沖模式相當容易,您可以通過以下方式完成:
- 在你的命令中傳遞一個
-u
標誌。python3
- 在您的環境中設置
PYTHONUNBUFFERED=1
(您可以在 systemd 服務單元中使用附加Environment=PYTHONUNBUFFERED=1
行進行設置。)您確認這適用於您的具體情況,太好了!
對於遭受類似問題的非 Python 應用程序,有諸如
unbuffer
和之類的命令行工具stdbuf
通常可以解決同樣的問題。解決方案通常特定於應用程序的類型,這有點令人遺憾,但通常在 Stack Exchange 中搜尋或尋找其他答案(一旦您知道緩衝是問題所在)通常會為您提供有用的建議。