我們有許多生產應用程式(第一方和第三方),它們將日誌記錄留給運行應用程式的進程,而只記錄stdout
forINFO
和stderr
forERROR
日誌(即只有 2 個日誌優先級INFO|ERROR
:)。
對於應用程式的 systemd 服務單元,可以這樣設定:
StandardOutput=journal
StandardError=journal
這使得 DevOps 可以透過 systemd 單元和日誌來管理一切,以便於集中式日誌收集、監控任何內容…並且他們無需擔心為部署的每個應用程式定位和解析不同格式/位置的不同日誌。
systemd 的日誌具有與 syslog 的 7 級訊息優先權系統相容的訊息優先權系統。 INFO
是水平6
,ERROR
是水平3
。有關更多詳細信息,請參閱參考資料。
問題是... systemd/journal 顯然不區分從 stdout 與 stderr 寫入日誌的訊息。 stdout 和 stderr 訊息都以預設優先權 6 ( INFO
) 寫入日誌。
範例:“精美應用程式”
/opt/log-test.sh
#!/bin/bash
echo "This is ERROR" 1>&2
echo "This is INFO"
exit 0
/etc/systemd/system/log-test.service
[Unit]
Description=log test for journal
[Service]
Type=simple
ExecStart=/opt/log-test.sh
StandardOutput=journal
StandardError=journal
SyslogIdentifier=log-test
運行它並檢查日誌
$ systemctl start log-test
$ journalctl -u log-test
-- Logs begin at Thu 2022-04-07 08:17:16 UTC, end at Thu 2022-04-07 16:35:02 UTC. --
Apr 07 16:34:58 host.example.com systemd[1]: Started log test for journal.
Apr 07 16:34:58 host.example.com log-test.sh[29909]: This is ERROR
Apr 07 16:34:58 host.example.com log-test.sh[29909]: This is INFO
$ journalctl -u log-test -p 6 # syslog info priority
-- Logs begin at Thu 2022-04-07 08:17:16 UTC, end at Thu 2022-04-07 16:35:08 UTC. --
Apr 07 16:34:58 host.example.com systemd[1]: Started log test for journal.
Apr 07 16:34:58 host.example.com log-test.sh[29909]: This is ERROR
Apr 07 16:34:58 host.example.com log-test.sh[29909]: This is INFO
$ journalctl -u log-test -p 3 # syslog error priority
-- No entries --
$
您可以看到,當寫入日誌時,stderr 和 stdout 訊息都設定為優先權6
( )。INFO
stdio->journal
這是一個問題,因為當用作主要日誌記錄工具時,我們沒有簡單的方法來區分 stdout 和 stderr 上的輸出。
這已經是之前討論過和解決方案是可能的,但是未實現。我希望 systemd 團隊最終能夠實現這一點,但同時我需要一個解決方案。
有沒有人找到合理的解決方案,使寫入 stdout 和 stderr 的訊息在日誌中具有不同的優先級無需修改應用程式的日誌記錄方式?
我不希望我們部署的所有應用程式(並非全部由我們編寫)都必須實現日誌或系統日誌集成,以便在我們實際上只需要兩個級別:INFO
(stdout)和ERROR
(stderr)時獲得日誌優先級。
我們部署的大部分內容都不是容器化的,因此依賴容器的日誌記錄設施也不是我們的解決方案。
預設情況下,讓 stderr 和 stdout 以不同的優先順序進入日誌/系統日誌對於使分散式日誌錯誤監控變得更容易非常關鍵(假設開發人員良好的衛生習慣,只編寫需要注意 stderr 的內容)。
參考:
答案1
如果你必須使用stdout
/ stderr
,你可以使用sd-daemon
日誌前綴。
stderr
在前面新增<3>
來發送ERROR
優先journald
日誌。
使用你的log-test.sh
和log-test.service
:
#!/bin/bash
>&2 echo "<3>This is ERROR"
echo "This is INFO"
exit 0
並journalctl
輸出:
$ journalctl -u log-test -p 3
May 02 01:22:58 host.example.com log-test.sh[29909]: This is ERROR
如果您fancy-app
有任何可寫入的 API syslog
,則可以使用它來寫入 UNIX 資料封包/dev/log
(通常預設可寫,並記錄到journald
)而不是stdout
/ stderr
。使用 syslog 標籤來識別您的fancy-app
syslog 優先權error
或info
根據您的需求以及任何 syslog 工具。
例如,在 Bash 中我們可以使用logger
:
# emit INFO message to journalctl
$ logger -t fancy-app -u /dev/log -p user.info "This is INFO"
# emit ERROR message to journalctl
$ logger -t fancy-app -u /dev/log -p user.error "This is ERROR"
# show journald messages for fancy-app
$ journalctl -t fancy-app
May 02 01:23:38 host.example.com fancy-app[27302]: This is INFO
May 02 01:23:39 host.example.com fancy-app[27303]: This is ERROR
# show journald ERROR messages for fancy-app
$ journalctl -t fancy-app -p 3
May 02 01:23:39 host.example.com fancy-app[27303]: This is ERROR
請注意,在大多數發行版中,條目journald
通常會轉送至本機系統日誌守護程式(syslog-ng
、rsyslog
、...),因此可能檢查您的系統日誌過濾器,或可能使用local0
...local7
設施。
我們有許多生產應用程式(第一方和第三方)將日誌記錄到容器中,僅將資訊記錄到 stdout,將錯誤日誌記錄到 stderr(即只有 2 個日誌優先權:INFO|ERROR)。
大多數容器引擎應該能夠記錄到系統日誌。在不了解容器引擎的情況下,我將使用 Docker 作為範例。
Docker 有系統日誌記錄驅動程式可用於使用 syslog 格式將日誌訊息傳送到任何 syslog 目標。您應該能夠journald
使用以下內容登入:
docker run \
--log-driver syslog \
--log-opt syslog-address=unix:///dev/log \
--log-opt syslog-facility=user \
--log-opt tag=fancy-app \
fancy-app:latest
Docker 還有日誌記錄驅動程式可用的。例如:
docker run \
--log-driver journald \
--log-opt tag=fancy-app \
fancy-app:latest
兩個日誌記錄驅動程式(系統日誌和紀錄) 支持stdout
和之間的分離stderr
;即stdout
訊息將被INFO
優先記錄,stderr
訊息將被ERROR
優先記錄。
拋開哲學和激烈的戰爭不談,為什麼不記錄到真正的系統日誌呢?比較簡單,以文字格式存儲,一般都有日誌管理軟體支援(參見格雷洛格,日誌儲存,紙跡)。