受け取っているアプリケーションを殺さずにLinux teeコマンドを終了する方法


19

Linuxマシンの電源が入っている限り実行するbashスクリプトがあります。以下に示すように開始します。

( /mnt/apps/start.sh 2>&1 | tee /tmp/nginx/debug_log.log ) &

起動後、ps出力にteeコマンドが次のように表示されます。

$ ps | grep tee
  418 root       0:02 tee /tmp/nginx/debug_log.log
3557 root       0:00 grep tee

ログが特定のサイズに達すると、teeが生成するログのサイズを監視し、teeコマンドを強制終了する機能があります。

monitor_debug_log_size() {
                ## Monitor the file size of the debug log to make sure it does not get too big
                while true; do
                                cecho r "CHECKING DEBUG LOG SIZE... "
                                debugLogSizeBytes=$(stat -c%s "/tmp/nginx/debug_log.log")
                                cecho r "DEBUG LOG SIZE: $debugLogSizeBytes"
                                if [ $((debugLogSizeBytes)) -gt 100000 ]; then
                                                cecho r "DEBUG LOG HAS GROWN TO LARGE... "
                                                sleep 3
                                                #rm -rf /tmp/nginx/debug_log.log 1>/dev/null 2>/dev/null
                                                kill -9 `pgrep -f tee`
                                fi
                                sleep 30
                done
}

驚いたことに、teeコマンドを削除すると、start.shインスタンスも削除されます。どうしてこれなの?teeコマンドを終了し、start.shを実行し続けるにはどうすればよいですか?ありがとう。

回答:


34

ときにtee終了、それはより多くの出力を書き込もうとするまで、それを供給するコマンドは、実行していきます。次に、リーダーなしでパイプに書き込もうとすると、SIGPIPE(ほとんどのシステムで13)を取得します。

SIGPIPEをトラップするためにスクリプトを変更し、適切なアクション(出力の書き込みを停止するなど)を実行する場合、Tが終了した後もスクリプトを続行させることができます。


さらに良いのは、tee まったく殺すのはなく、単純化のためにlogrotateこのcopytruncateオプションを使用することです。

引用するにはlogrotate(8)

copytruncate

古いログファイルを移動し、オプションで新しいログファイルを作成する代わりに、コピーの作成後に元のログファイルを切り捨てます。一部のプログラムにそのログファイルを閉じるように指示できないため、以前のログファイルへの書き込み(追加)を永久に続ける場合に使用できます。ファイルのコピーと切り捨ての間には非常に短いタイムスライスがあるため、一部のログデータが失われる可能性があることに注意してください。このオプションを使用すると、古いログファイルがそのまま残るため、作成オプションは効果がありません。


9
を使用tee -ateeて追加モードでファイルを開くこともできます。そうしないと、teeはファイルを切り捨てた後、同じオフセットでファイルに書き込みを続けます(macOSのようにスパースファイルをサポートしないシステムではその位置までのファイルのセクションを再割り当てし、2倍のディスク容量を消費します)。
ステファンシャゼラス

4
他のオプションはlogger -s、syslogにログを送ってログを処理することです(-sstderrに印刷することもできます)。
ステファンシャゼル

1
+1 logrotate。素晴らしいプログラム
ドミトリークドリャフツェフ

2
または、systemdおよびjournaldを使用するシステムで、ロガーの代わりにsystemd-cat。その後、多くの出力フィルタリングとローテーションを無料で入手できます。
ザンリンクス

3

「なぜ」の説明

つまり、書き込みが失敗してもプログラムが終了しない場合(デフォルト)、混乱が生じます。考えてみてくださいfind . | head -n 10- 必要な10行を取得して先に進んだfindheadは、ハードドライブの残りの部分をスキャンして、走り続けたくありません。

より良い方法:ロガー内での回転

tee実証的な例として、まったく使用しない以下を検討してください。

#!/usr/bin/env bash

file=${1:-debug.log}                     # filename as 1st argument
max_size=${2:-100000}                    # max size as 2nd argument
size=$(stat --format=%s -- "$file") || exit  # Use GNU stat to retrieve size
exec >>"$file"                           # Open file for append

while IFS= read -r line; do              # read a line from stdin
  size=$(( size + ${#line} + 1 ))        # add line's length + 1 to our counter
  if (( size > max_size )); then         # and if it exceeds our maximum...
    mv -- "$file" "$file.old"            # ...rename the file away...
    exec >"$file"                        # ...and reopen a new file as stdout
    size=0                               # ...resetting our size counter
  fi
  printf '%s\n' "$line"                  # regardless, append to our current stdout
done

として実行する場合:

/mnt/apps/start.sh 2>&1 | above-script /tmp/nginx/debug_log

...これは、に追加することから始まり、100KBを超えるコンテンツが存在/tmp/nginx/debug_logする/tmp/nginx/debug_log.old場合にファイルの名前を変更します。ロガー自体が回転を行っているため、回転が発生してもパイプの破損、エラー、データ損失のウィンドウはありません。すべての行が1つのファイルに書き込まれます。

もちろん、これをネイティブbashで実装するのは非効率的ですが、上記は説明のための例です。上記のロジックを実装するプログラムは多数あります。考慮してください:

  • svlogd、Runitスイートのサービスロガー。
  • s6-log、スカネットスイートからの積極的に維持される代替。
  • multilog このプロセス監視および監視ツールのファミリーの祖父であるDJB Daemontoolsから。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.