前回に引き続き、systemd-journald(以下、journald)について解説します。今回はrsyslogとの関わりを中心に、journaldを見ていきます。
journaldによるログの受信とrsyslogへの転送
systemd環境ではjournaldがシステムやサービスのログを一手に集めています。一方で、Ubuntuでは従来からのログ収集・格納サービスであるrsyslogが現在も稼働しています。おそらく、後方互換性のためと筆者は考えています。
詳しくは後述しますが、実際にはsystemd環境ではjournaldがまずシステム上のログを受け取り、必要に応じてrsyslogへログを転送しています。
たとえば、journaldは/dev/kmsg
を通じてカーネルログを集めていますし、/dev/log
より従来のsyslog宛てのログも集めています。もちろん、ネイティブのjournalプロトコルを通じて送られてくる、ジャーナルに書き込むべきログも集めています。
標準出力・標準エラー出力からのログの記録を確かめる
筆者がすこし変わっていると思うのは、サービスユニットの標準出力および標準エラー出力もジャーナルに記録している点です。
簡単に検証してみます。以下のような、標準出力および標準エラー出力にメッセージを出力するスクリプトを作成し、適切に実行権限を付与します。ファイル名はjournald-stdout-verify.sh
とします。
一時的なユニット生成・実行できるsystemd-run
コマンド[1]を使って、このスクリプトを一時的なサービスとして実行します。
Running as unit: run-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.service
と表示されます。
このサービスのジャーナルを見ると、標準出力と標準エラー出力が記録されていることを確認できます。
標準出力・標準エラー出力のrsyslogへの転送
Ubuntuではjournaldとrsyslogとのどちらもが動いていますが、journaldがまずこれらのログを読み取ります。
そして、journaldが入手したすべてのログがrsyslogへ転送されます。Ubuntuのデフォルトでは/etc/systemd/journald.conf
の設定がForwardToSyslog=yes
でMaxLevelSyslog=debug
になっているからです。
systemdの場合はデフォルトで、サービスの標準出力および標準エラー出力もjournaldにつながっているため、その内容はsyslogにも転送されています。
しかしSysV系initの場合は、サービスデーモンは標準出力および標準エラー出力を/dev/null
につないでいるため、ログは必要に応じてrsyslogなどに投げていました[2]。
このような挙動から、サービスの仕様や設計、動作、journald側の設定にもよりますが、同じサービスにもかかわらず、SysV系initではsyslogに表示されていなかったメッセージが、systemdのシステムの場合は表示されることがありえます。つまりsyslogを眺めることで、一方の環境ではエラーが出るにもかかわらず、他方の環境ではエラーが出ないといったトラブルシューティングの役には立つ可能性があります。
どこで収集されたログかを確認する
各ログについてjournaldがどこから収集したものかは、詳細ログの_TRANSPORT=
フィールドで確認できます。
_TRANSPORT=
フィールドを確認するためには、-o verbose
を付与してjournalctl
を実行します。以下は、先ほどのjournald-stdout-verify.sh
を実行したときのログの例です。
_TRANSPORT=stdout
となっているとおり、標準出力・標準エラー出力からログが収集されていることを確認できます。
なお、systemdの開発者であるLennartPoetteringのブログ記事ではsyslog()
、printf()
、sd_journal_send()
と、journaldにログを拾わせる3つの方法を紹介しています。詳細が気になる方はこちらも参照してください。
フィールド
話の流れで先に_TRANSPORT=
フィールドを取り上げましたが、journaldのフィールドについて簡単に触れておきます[3]。
フィールドには大きく分けて2種類、ユーザージャーナルフィールドとトラステッドジャーナルフィールドがあります。
ユーザージャーナルフィールドはサービスなどが報告してきた情報が記録されるフィールドです。メッセージ本文を示すMESSAGE=
や文字通りプライオリティを示すPRIORITY=
、syslogとの互換性のためのSYSLOG_FACILITY=
、SYSLOG_IDENTIFIER=
、SYSLOG_PID=
などです。
ちなみにjournald-stdout-verify.sh
からの標準出力を記録したログでは、PRIORITY=6
(info)であることを確認できます。
一方、トラステッドジャーナルフィールドはjournaldにより情報が付与されるフィールドで、フィールド名の先頭に_
が付与されています。特徴として、これらの情報はjournald側でのみ記録が可能なことです。ログを送ってくる側の都合で設定や変更はできません。そのような性質から、「信頼できる(trusted)」フィールドと言えます。
たとえば、ログを送ってきたプロセスのID_PID
や実行ユーザーのID_UID
などがあります。先ほどの_TRANSPORT
も先頭に_
があり、こちらに該当します。
なお、_BOOT_ID=
は次項各カーネルの起動ごとに割り振られるランダムなIDです。これで、どのブート時のログかを区別できます。
ブートごとのIDは--list-boots
オプションを付けることで確認できます。
ジャーナルを残す設定の場合、あるブートの時のログを確認するオプション-b
は${_BOOT_ID}±n
という形式を取ることも可能です。これにより、あるブート時のログから相対的にn回前・後のブートを指定してジャーナルを確認できます。
ログは誰の手に?
一部ではありますが、前回と今回でsystemdでのログ収集・管理について解説してきました。
journald.confのmanページにある記述ではsyslogに"traditional"の形容詞がついていることからも、syslogの置き換えを目指してjournaldやjournalctlがつくられていることが窺えます。ログを集めて管理し、閲覧するという点では、journaldやjournalctlは十分に実用的なレベルになっているしょう[4]。
一方で、すでに述べたとおり、Ubuntuではrsyslogが併用されています。サーバーの監視ソフトウェアなどがsyslogのログデータを読む限り、当面の間syslogの出番がまったくなくなることはないとは思います。
逆に、そのようなサーバー用途でもない限り、journaldだけでいいのではないか、という考え方もできそうです。よって、デスクトップ版のUbuntuではjournaldだけが動いているという未来はそう遠くはないタイミングに訪れるのでは、と筆者は考えています。