コマンドをパイプでつなげると並列で動作する

昨日の記事に関連するメモ

nanka.hateblo.jp

完全に勘違いしていました。

パイプを繋ぐと左からコマンドが順次実行されるとばかり思い込んでいましたが、並列でそれぞれ動作してるんですね..

極端なはなしですが↓を実行すると即座に2が出力されて3秒後に1が出力されて終了する

$ sleep 3 | (read i; echo '1' 1>&2) | echo '2'

標準入力を受け取るコマンドが正しく動いているのは、入力待ち状態になっているから

上の例で言うと read i がsleep3の出力を待っているので、2 -> 1の順で出力される

よくよく考えたらあたり前のことだった..

パイプはその名の通り、それぞれのプロセスの入出力をつなぎ合わせてるだけだと覚えればよさそう

ログファイルを監視してslackに通知する

仕事で使った

準備

通知用にincoming webhookの設定をする

↓のURLからURLを発行する

api.slack.com

通知用のrubyスクリプト

※4/21追記

いろいろ勘違い等があり、紆余曲折あって↓のように変更した

nanka.hateblo.jp –ここまで

使用したrubyのバージョン

$ ruby -v
ruby 2.0.0p648 (2015-12-16 revision 53161) [x86_64-linux]
require 'net/http'
require 'uri'
require 'json'

uri = URI.parse("https://hooks.slack.com/services/*/*/*")

text = ARGV[3]

if File.pipe?(STDIN) || File.select([STDIN], [], [], 0) != nil then
  text ||= STDIN.read
end

exit unless text

payload = {
  text: text,
  channel: ARGV[0],
  username: ARGV[1],
  icon_emoji: ARGV[2]
}

Net::HTTP.post_form(uri, { payload: payload.to_json })

こんな感じで使える

ruby slack.rb "#room" "name" ":ghost:" "hoge"
echo "hoge" | ruby slack.rb "#room" "name" ":emoji:"

tail,grepと組み合わせて特定のログが書き込まれた際にslackに通知

ワンライナーにしてtmux上で動かしている

tail -n 0 -F logfile | grep --line-buffered "hoge" | while read i; do ruby slack.rb "#room" "name" ":emoji:" "$i"; done

tailの挙動がよくわからずに、ここまで作るのに結構時間がかかってしまった

以下はいくつかハマった?ポイント

監視対象が毎日貼り変わるシンボリックリンクだった

当初 tail -f しか知らなかったので、貼り変わった時どうしようか少し悩んでしまった

-F オプションにすることで、リネームされたときやシンボリックリンクが貼り変わった時でも自動で追従してくれる(らしい)

grepした結果が通知されない

tail -n 0 -F logfile | grep "hoge" | while read i; do ruby slack.rb "#room" "name" ":emoji:" "$i"; done

としてると全然通知されなかった

grep--line-buffered オプションを付けることで問題は解決した

どうやら出力バッファリングという機能が邪魔をしていたらしい

tail -Fの結果をパイプで渡すとruby側で上手に捌けない..?

tail -Fが特殊な挙動をすることが原因だと思いこんでいるが、

tail -F logfile | ruby slack.rb "#room" "name" ":emoji:"

とすると、どこかのタイミングで標準入力がない状態で↓のif文が通ってしまい、STDIN.readでキーボード入力待ちになってしまう場合がある

if File.pipe?(STDIN) || File.select([STDIN], [], [], 0) != nil then
  text ||= STDIN.read
end

そこで while read i で一度受け取るようにしたら、正しく動くようになった

tail -F logfile | while read i; do ruby slack.rb "#room" "name" ":emoji:" "$i"; done

原因がわからないのが気持ち悪い、いつかtailの実装を読んでみたい

※4/21追記

原因については↓

nanka.hateblo.jp –ここまで

久しぶりに外でお酒を飲みました

土曜日にとある小さい業界の社長さんとご飯を食べる機会があった

その方は、50前で僕と一回りも年齢が離れているにもかかわらず、かなり熱い思いを持っている人だった

その世代になると、目標がなくなってしまってる人も多いイメージだったので衝撃的だった

協力できることはしていきたいな