追加読書

追加読書

システムサービスとして実行されるシェルスクリプトがあり、メッセージを記録したいと思います。細かい優先順位を持つサービスの systemd ログを入力します。

ジャーナリングを使用すると、logger(1)一部のメッセージのみが記録され、残りは削除されます。どのメッセージがサービスログに記録されるかは完全にランダムであるようです。時には1つまたは2つのメッセージだけが記録され、時にはメッセージはまったく記録されません。

journalctl --system最初は起動順序/依存関係の問題だと思いました。ただし、すべてのメッセージがシステムログ(例:)には表示されますが、サービスログ(例journalctl -u SERVICE.service)には表示されないため、そうではありません。私も試してみましたが、systemd-cat残念ながら同様に動作します。

スクリプトベースのサービスが優先順位メッセージを独自のシステムログに記録する正しい方法は何ですか?

答え1

systemdが直面する問題は、logger独自のツールsystemd-notifyが直面する問題と同じです。このプロトコルはデータグラムに基づく非同期プロトコルであり、ツールは1つの操作のみを完了します。呼び出し側は、ツールを実行するためにプロセスを分岐します。データグラムがエクスポートされ、そのプロセスは終了します。

systemdログ記録と準備通知プロトコルのためのサーバープロセスは、送信者がどのサービスに属しているかを知りたいと思います。 Linux でデータグラムの送信者のプロセス ID を取得し、プロセステーブルに移動して、プロセスが属する制御グループとプロセスが属するサービスを探します。

転送プロセスがタスクを完了してすぐに終了する場合は機能しません(競争条件によって異なります)。プロセスがプロセステーブルに存在しなくなりました。 systemd-notify通知に失敗しました。loggerメッセージは関連サービスに属するものとしてマークされません。ストリーミングプロトコルに切り替えても(例:logger's--tcpオプションを使用しても)問題は解決されません。〜しない限りロギングプロトコル自体は返品クライアントはストリームを閉じて終了する前にサーバーの応答を待つように変更されましたが、そうではありません。 RFC 5426サーバーの承認はクライアントに再送信されません。

したがって、ログ情報がログにある間は、サービス名でタグ付けされず、サービス名で照会してもインポートされません。 (しかし、これは私が思うように別々のログではありません。1つの journalctl大きなログに適用されるフィルタだけです。 -uフィルタです。)

これはずっと前からよく知られている間違いです。

人々はsystemdこれをLinuxの欠陥と説明しています。プロセスセットをカプセル化して追跡するために使用できる適切な作業オブジェクトはありません。対応するデータグラムソケットメカニズムAF_LOCALもそのような情報を送信しません。そうでsystemdあれば、すべてのサービスプロセスを1つのジョブに配置でき、そのログ記録と準備通知サーバーは、クライアントプロセスが終了してもデータグラムを受信したときにクライアントジョブ情報を抽出できます。

system-journald一部のバージョンloggerでは動作する特別なプロトコルがあります。いいえ、_SYSTEMD_UNITこれはサーバーによって設定された「信頼できるフィールド」です。これを設定しようとするクライアントのすべての試みは無視されます。これもデータグラムに基づく非同期プロトコルなので、確認は不要です。同じ問題があります。

正しいサービスでログエントリに確実にタグを付けるには標準エラーに書き込む。これにより、長寿命でサーバー側のサービスユニット名へのより信頼性の高い接続が可能になります。はい、レガシー施設と優先順位を指定することはできません。

追加読書

答え2

@JdeBPの非常に便利な回答で、私のメッセージが正しいサービスログに表示されるようにする方法を見つけることができました。問題は、HarvestjournaldとHarvestの間の競合状態で発生するため、次の寿命のlogger長い中間データグラムを持つことができます。各スクリプト/サービスについて。これにより、journald転送プロセスが常に見つかります。

socat次の関数は、まだ起動していない場合はリレーを起動し、デフォルトではなくloggerリレーソケットに送信するようにメッセージを設定します。親スクリプトが終了すると、リレーは自動的に終了し、対応するソケットを削除します。

# Usage:  builtin_logger  TAG SEVERITY MESSAGE
builtin_logger() {
    if [[ "${SHELL_SERVICE_LOG_SOCK-}" == "" ]]; then
        declare -g SHELL_SERVICE_LOG_SOCK
        SHELL_SERVICE_LOG_SOCK="/tmp/service-log.$$"
        sh -c "socat UNIX-RECV:'$SHELL_SERVICE_LOG_SOCK' UNIX-SENDTO:'/dev/log' &
               SOCAT_PID=\$!
               trap \"if [ -e '$SHELL_SERVICE_LOG_SOCK' ]; then rm '$SHELL_SERVICE_LOG_SOCK'; kill \$SOCAT_PID; fi\" EXIT INT TERM
               tail --pid=$$ -f /dev/null" & 
        sleep 0.1 # waiting for socat to run (TODO inotify)
    fi
    logger -u "$SHELL_SERVICE_LOG_SOCK" -t "$1" -p user."$2" "$3"
}

関連情報