ログユーティリティのキーワード検索またはタイムアウト追跡

ログユーティリティのキーワード検索またはタイムアウト追跡

私はGoogleにアクセスするための特別な方法を使用しています。これでページが大きく変わりました。したがって、通常は質問を編集し、答えにコメントすることができます。以前のディスカッションをさらに削除し、ポイントを整理しました。

スクリプトが次のコマンドを実行するキーワードを見つけたら、テーリングを停止して0を返したいと思います。 1分後にキーワードが見つからない場合は、スクリプト全体が停止し、エラーコードが返されます。set -euxo pipefailぜひ必要で使用しています。

timeout 1m tail -Fn 0 --pid=$(ps -ef | grep "sed /$keywords" | grep -v grep | awk '{print $2}') $log_file | sed "/$keywords/q"

以前に使用した上記のコマンドは、テスト時に正しく接続されました。しかし、Jenkinsでは、キーワードが見つかると、「ビルドステップ 'シェル実行'がビルドを失敗としてマークしました。」を返すことがあります。

プログラムを手動で再起動した後、原因を見つけました。コード141を返します。そのため、コードを確認してみると、tail -fパイプラインと関連があることがわかりました|http://www.pixelbeat.org/programming/sigpipe_handling.html


私の目的のために他の質問のコマンドを修正しました。 「tail-Fn 0 balabala.log」がまだバックグラウンドに残り、数分後に消えることを除いて、すべてが大丈夫です。しかし、目標に最も近いです。

{ sed /"$keywords"/q; kill -13 $!; } < <(exec timeout 1m tail -Fn 0 $log_file)

これは私が理解できないことです...使用法を探しましたが、それでも確信はありません。

  1. 代わりにスクリプトをkill -s PIPE "$!"短縮しました。kill -13 $!
  2. まだの使い方が混乱します{ } < <()。私にとっては外国語のような言葉です...
  3. exec削除できますか?使わないのとは違うようです。
  4. tail裏面に問題があるのでしょうか?同時に複数のプログラムを起動すると危険ですか?

Jenkinsログは次のとおりです。

......
+ keywords='cloud-service-notice has been started successfully'
+ log_file=/data/jars/logs/info.cloud-service-notice.log
+ cd /data/jars/cloud-service-notice
+ nohup java -jar /data/jars/cloud-service-notice/cloud-service-notice.jar --spring.profiles.active=test
+ sed '/cloud-service-notice has been started successfully/q'
++ exec timeout 1m tail -Fn 0 /data/jars/logs/info.cloud-service-notice.log
2019-07-02 10:31:12,544 [main] INFO  o.s.c.a.AnnotationConfigApplicationContext.prepareRefresh[588] - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@54a097cc: startup date [Tue Jul 02 10:31:12 CST 2019]; root of context hierarchy
......
2019-07-02 10:31:33,860 [main] INFO  c.enneagon.service.notice.NoticeApp.main[24] - cloud-service-notice has been started successfully
+ kill -13 20021
+ ssh web01 'cd /data/releases/cloud-service-notice/20190702-104108/.. &&' 'ls -1 | sort -r | awk '\''FNR > 20  {printf("rm -rf %s\n", $0);}'\'' | bash'
Finished: SUCCESS

プロセス20021はですtimeout 1m tail -Fn 0 balabala.log。スクリプトが完了した後も、プロセス20023はtail -Fn 0 balabala.logまだ存在し、数分後に消えました。

[root@web01 scripts]# ps -ef | grep notice
root     20020     1 27 10:41 ?        00:01:07 java -jar /data/jars/cloud-service-notice/cloud-service-notice.jar --spring.profiles.active=test
root     20023     1  0 10:41 ?        00:00:00 tail -Fn 0 /data/jars/logs/info.cloud-service-notice.log
root     20461 18966  0 10:45 pts/1    00:00:00 grep --color=auto notice

このコマンドで私の質問に答えたいのですが、わかりません。ローカルコンピュータでテストした後、さらにテストするために本番環境に配置しました。


多くのテストの最後に、ついにコマンドを次のように変更しました。

{ sed /"$keywords"/q; kill $!; } < <(exec timeout 1m tail -Fn 0 $log_file)

-13今削除しました。だから滞在するのですtail -Fn 0 balabala.log。上記の4つの質問におおよそ答えることができます。

  1. kill -15このコマンドを追加したので、より良いですtimeout$!うん、pid timeouttail -Fn 0 balabala.log以下は、デフォルト番号15を使用して終了できる子プロセスです。
  2. プロセス交換とマルチプロセス使用のみです{...}kill1分後にtimeoutバックグラウンドで自分で終了するため、無視することもできます。したがって、このコマンドは:なしでkillまだ受け入れられますsed /"$keywords"/q < <(exec timeout 1m tail -Fn 0 $log_file)。この場合、常に0を返します。
  3. そうでないことをお勧めします。コマンドを実行すると、2つの親プロセスが表示されます。ところでやったら大丈夫だよ。
  4. その理由は上記の「1」にあります。timeout殺されたがtail残された。

答え1

次のことができます。

sh -c 'echo "$$"; exec tail -f file' | (
  IFS= read -r pid
  timeout 60 sed "/$keyword/q"
  kill -s PIPE "$pid"
)

そのオプションを有効にしないと、それ自体が終了しない限り、終了ステータスは0pipefailで終了します(実際には発生しないでください)。killtail

使用すると、pipefailSIGPIPEによって終了ステータスが終了しますtail(値が141のほとんどのシェルに表示されます)。|| true正常な終了状態を強制するために、いつでもaを追加できます。

また見なさい:

答え2

私の考えでは、ここで何が起こっているのかは競争条件です。シャットダウンのために破損したパイプに書き込もうとしているSIGPIPE(通常128 + 13 = 141シャットダウンステータスに対応する信号13)を受信する前に、追跡されたPIDがシャットダウンしていることを確認して認識tail --pid=...してください。これtailsed手動「プロセスが終了した直後にテールも終了します」としか記載されていないため、確認が頻繁に発生しない場合があります。

とにかくtailSIGPIPEによって終了した場合、これは(通常)目的の行を取得してsed終了したことを意味します。返品成功の条件になります。if回避するには、ブロックを使用しset -eて終了ステータスを明示的に確認して、まったく同じように処理することをお勧めします。

if timeout tail ... | sed ...; ret=$?; then
    : # do nothing, success
elif [ "$ret" != 141 ]  # not sigpipe, sed didn't quit, so failure
    exit "$ret"
fi

ナレーター:スクリプトが#/bin/bash。これがなければ、スクリプトはshを使用して実行され、おそらくプロセスオーバーライドを使用しようとしている理由です(はい#!#<(...)プロセス、コマンドではなく置換)は構文エラーです。慎重に確認してください。

シングルライナーが欲しいと言われましたが、複雑なシングルライナーは、保守性の点で常に最善の解決策ではありません。実行中の作業を簡単に記録するには、複数行を使用してください。

答え3

命令が見つかりました。詳細は質問にあります。

{ sed /"$keywords"/q; kill $!; } < <(exec timeout 1m tail -Fn 0 $log_file)

#!/bin/bashset -euxo pipefailスクリプトにおよびが必要な場合は、bashCentOSはスクリプトshをに接続せずに実行する必要があります。bash

関連情報