LoginSignup
4
7

More than 5 years have passed since last update.

timeout と tail で1秒間のリアルタイムなログを集計する

Posted at
  • CentOS 7.2.1511
  • bash 4.2.46
  • coreutils 8.22

例えば、急にものすごいアクセス数が増えていて、1秒間のリアルタイムなログを集計したいときとか。

次のようにすれば Apache のアクセスログから IP アドレスで集計した結果を得られます。

cat access_log | awk '{print $1}' | sort | uniq -c | sort -rn

リアルタイムに書き込まれたログを表示するといえば tail -f ですが、次のようにしても、

tail -n0 -f access_log | awk '{print $1}' | sort | uniq -c | sort -rn

tail を止めるために Ctrl+C するとパイプ先のプロセスまで一緒に死んでしまいます。

timeout を使う → 失敗

timeout を付けて tail を実行してみます。

timeout 1 tail -n0 -f access_log | awk '{print $1}' | sort | uniq -c | sort -rn

だめでした。タイムアウトしたときにパイプ先のプロセスまで死んでいます。

timeout はタイムアウトしたときにプロセスグループを皆殺しにしていました。

言い換えると、上の書き方でパイプ先にまでタイムアウトを掛けることができているということですね。

timeout --foreground を使う

man timeout によると --foreground をつけると大丈夫そうなのでやってみました。

timeout --foreground 1 tail -n0 -f access_log | awk '{print $1}' | sort | uniq -c | sort -rn

成功です、開始から1秒で tail だけ死んで集計結果が表示されました。

timeout と setsid を使う

CentOS 6 の timeout だと --foreground がありませんでした・・

timeout がプロセスグループ皆殺しにするのをどうにかすればいいだけなので、パイプ先で setsid してプロセスグループが変わるようにしてみました。

timeout 1 tail -n0 -f access_log | setsid sh -c "awk '{print \$1}' | sort | uniq -c | sort -rn"

成功です。

timeout と timeout を使う

次のようにパイプ先で timeout しても大丈夫でした。

timeout 1 tail -n0 -f access_log | timeout 2 sh -c "awk '{print \$1}' | sort | uniq -c | sort -rn"

timeout はプロセスグループを皆殺しにするために setpgid(0, 0) でプロセスグループリーダーになるようです。

なので↑のようにすると先頭の timeout とパイプ先の timeout でプロセスグループが変わり、先頭の timeout がパイプ先の timeout を殺せなくなります。

例えば、次のようにすると3つの sleep は別々のプロセスグループになりますし、Ctrl+C でも死ぬのは最初の sleep だけになります。

timeout 30 sleep 30 | timeout 30 sleep 30 | timeout 30 sleep 30
pstree -agp 1318
# bash,1318,1318
#   ├─timeout,17993,17993 30 sleep 30
#   │   └─sleep,17998,17993 30
#   ├─timeout,17994,17994 30 sleep 30
#   │   └─sleep,17997,17994 30
#   └─timeout,17995,17995 30 sleep 30
#       └─sleep,17996,17995 30

--foreground をつけるとこの動きが変わり、3つの sleep が全部同じプロセスグループになりました。

timeout --foreground 30 sleep 30 | timeout --foreground 30 sleep 30 | timeout --foreground 30 sleep 30
pstree -agp 1318
# bash,1318,1318
#   ├─timeout,18008,18008 --foreground 30 sleep 30
#   │   └─sleep,18013,18008 30
#   ├─timeout,18009,18008 --foreground 30 sleep 30
#   │   └─sleep,18011,18008 30
#   └─timeout,18010,18008 --foreground 30 sleep 30
#       └─sleep,18012,18008 30

この場合は timeout は直接の子プロセスだけ殺します。

4
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
7