置き換えられたログファイルと標準出力にスクリプト出力を書き込むにはどうすればよいですか?

置き換えられたログファイルと標準出力にスクリプト出力を書き込むにはどうすればよいですか?

私たちはコンテナ内でマイクロサービスをK8sポッドとして実行します。アプリケーションがコンテナに送信されたすべての信号(特にポッドを削除するときにSIGTERM)を受け取るようにするために、通常は起動スクリプトの最後に使用され、起動スクリプトのexecbashプロセス(PIDは1)がアプリケーションプロセスに効果的になります。したがって、起動スクリプトは通常次のように終了します。

exec <ourCommand>

便宜上、ログ出力(stdoutとstderr)をの出力に表示したいkubectl logsが、事後分析のために出力をファイルで終わりたい(例えば、そのファイルは存在する場所で終わる)。ポッドが再起動します。 -)).ファイルが大きくなりすぎないようにするには、ファイルを回転させる必要があります。ログローテーションの場合、rotatelogsApacheツールの良い経験があります。 「-e」オプションは、「stdoutへのエコーログ」を指定して、ファイルとstdoutのロギング出力を提供します。最も明白な方法は、次のようにスクリプト出力をパイプすることです。

exec <ourCommand> | rotatelogs -e -n 10 stdout.log 10M

exec これはうまく機能しているようですが、予想される動作を効果的に防ぎ、起動スクリプトがまだルートプロセスであることがわかりました。たとえば、pstree -p 次の構造が表示されます。

start.sh(1)-+-<ourCommand>(17)
        `-rotatelogs(18)

したがって、信号処理が中断され、アプリケーションがSIGTERMを受信せずに正常に終了しなくなり、代わりに終了猶予期間が終了した後にPodが終了します。

多くの試行錯誤の後、私たちはプロセス代替を使用してこのソリューションに達しました。 exec <ourCommand> &> >( rotatelogs -e -n 10 stdout.log 10M)

結果は、所望のプロセス構造と再び動作する信号処理である。pstree -pこれでこの構造が表示されます。

<ourCommand>(1)---start.sh(17)---rotatelogs(18)

しかし、我々はポッドがクラッシュする状況を繰り返し発見し、時には目立つエラーメッセージも表示されませんでしたkubectl logs(しかし以前はログファイルに表示されますが、そこを見ている人は同じ内容を持つことを期待していないので、kubectl logs「なぜ面倒な」のですか?興味深いことに、これは本番環境(EKSおよびAKSクラスター)でより頻繁に発生し、ローカル環境(minikube)で問題を再現しようとすると安定性が低下します。

最も良い推測は、rotatelogsが常に出力バッファをフラッシュするわけではないため、特にスクリプト出力の最後の行(通常は役に立つエラーメッセージ...)が失われる可能性があることです。 Rotatelogsは各行を強制的に更新する設定を提供していないので、この方法を使用することをお勧めします(「デュアルプロセスの置き換え」と呼ばれます)。

exec <ourCommand> &> >(tee >(rotatelogs -n 10 stdout.log 10M ))

アイデアは、ティーに「ストリーム分割」を実行させることであり、回転するログで発生するフラッシュの問題がないため、うまく-e機能します。クラッシュしたアプリケーションの「有名な最後の単語」がログファイルに確実に表示されます。 、そしてkubectl logs

その後、誰かがTSフィルタリングを介してすべてのログ行にタイムスタンプを取る素晴らしいアイデアを思いついた。

exec <ourCommand> &> >(ts | tee >(rotatelogs -n 10 stdout.log 10M ))

これは最終的に「有名な最後の単語」がしばしば現れないという事実につながりますkubectl logs。現在のプロセス構造は次のとおりです。

<ourCommand>(1)---start.sh(17)-+-tee(19)---start.sh(20)---rotatelogs(21)
                               `-ts(18)

はい、「トリプルプロセスの交換」を試しましたが、-Dの問題は解決されませんでした。 tsを削除するだけです。

Bashをより深く理解している人なら、ここで何が起こっているのかを説明できますか(そして可能な解決策を提案できますか?)

ありがとう

答え1

tsタイムスタンプを追加して印刷する前に、行全体を受け取ることが期待されます。したがって、プロセスの「最後の単語」が - で終わらないと\n失われる可能性があります。

どうすれば修正できますか?自分で書いてみtsてください。次のようになります。

#!/bin/perl
$foundLF = 1;

while($ch=getc) {
    if ($foundLF == 1) {
        $datestring = gmtime();
        print "$datestring ";
        $foundLF = 0;
    }

    print $ch;

    $foundLF = 1 if (ord($ch) == 10);
}

ts作成されているのでperl参考にしてください。

その機能を自分の機能にtee含めることで簡単に実行できます。rotatelogtsperl

関連情報