Overview
inotifywait
に関してはこのあたりが詳しいのでこちらを参照。
https://qiita.com/hana_shin/items/9e03ad7a40b4fd7afb67
inotifywait でファイルを監視するまでは調べるとよく出てくるけど、
モニターの結果を通知するいい感じの方法が見付からなかったので、試した。
準備
docker
+ centos:7
で試します。
version: '3'
services:
os:
image: centos:7
tty: true
コンテナが即終了しないように tty: true
を付けてる。
起動
docker-compose up
コンテナに入る
centos7が立ち上がってるので、bashで入る。
docker-compose exec os bash
パッケージなど
yum update -y
yum install -y epel-release
yum install -y inotify-tools
yum install -y jq nc
jq
と nc
は後で使います。
監視してみる
ファイルを準備
[root@92790f6e5f76 /]# pwd
/
[root@92790f6e5f76 /]# mkdir a
[root@92790f6e5f76 /]# echo test > /a/test.txt
実行
--format
指定がややこしいことになってますが、 \t
がタブ文字に展開されないので愚直に繋いでます。
理由は後述。
inotifywait -m --format "%T"$'\t'"%w"$'\t'"%f"$'\t'"%e" --timefmt '%F %T' /a
変更してみる
別のシェルで入って
touch /a/test.txt
とかやると、
[root@92790f6e5f76 /]# inotifywait -m --format "%T"$'\t'"%w"$'\t'"%f"$'\t'"%e" --timefmt '%F %T' /a
Setting up watches.
Watches established.
2019-07-09 04:28:20 /a/ OPEN,ISDIR
2019-07-09 04:28:20 /a/ ACCESS,ISDIR
2019-07-09 04:28:20 /a/ CLOSE_NOWRITE,CLOSE,ISDIR
2019-07-09 04:28:21 /a/ test.txt OPEN
2019-07-09 04:28:21 /a/ test.txt ATTRIB
2019-07-09 04:28:21 /a/ test.txt CLOSE_WRITE,CLOSE
みたいに出力されます。
%e
がイベント名のcsvに展開されるため、それ以外の部分をtsvにしたかった感じですね。
整形する
1行ずつのtsvにできたので、後々処理しやすいように jsonl に整形します。
inotifywait -m --format "%T"$'\t'"%w"$'\t'"%f"$'\t'"%e" --timefmt '%F %T' /a \
| jq -R -c '{hoge: .|split("\t")}'
touch /a/test.txt
出力はこんな感じ。
{"hoge":["2019-07-09 04:35:10","/a/","test.txt","OPEN"]}
{"hoge":["2019-07-09 04:35:10","/a/","test.txt","ATTRIB"]}
{"hoge":["2019-07-09 04:35:10","/a/","test.txt","CLOSE_WRITE,CLOSE"]}
1行ずつ処理する
が、このままだとまるごと1本のストリームなので、while read
で1行ずつ処理するように修正します。
inotifywait -m --format "%T"$'\t'"%w"$'\t'"%f"$'\t'"%e" --timefmt '%F %T' /a \
| while read x; do
echo "$x" | jq -Rc '{hoge: .|split("\t")}';
done
touch /a/test.txt
見た目は同じ。
{"hoge":["2019-07-09 04:38:33","/a/","test.txt","OPEN"]}
{"hoge":["2019-07-09 04:38:33","/a/","test.txt","ATTRIB"]}
{"hoge":["2019-07-09 04:38:33","/a/","test.txt","CLOSE_WRITE,CLOSE"]}
通知
さて、これで1行ずつ json にして処理できるようになったので、とりあえず curl で投げてみます。
nc で簡易httpサーバを立てて、
while true; do { echo -e 'HTTP/1.1 200 OK\r\n'; echo "OK"; } | nc -l 8080; done
監視を開始。
inotifywait -m --format "%T"$'\t'"%w"$'\t'"%f"$'\t'"%e" --timefmt '%F %T' /a \
| while read x; do
echo "$x" | jq -Rc '{hoge: .|split("\t")}' | curl localhost:8080 -H 'Content-Type: application/json' -d @-;
done
変更すると、
touch /a/test.txt
POST / HTTP/1.1
User-Agent: curl/7.29.0
Host: localhost:8080
Accept: */*
Content-Type: application/json
Content-Length: 56
{"hoge":["2019-07-09 04:44:18","/a/","test.txt","OPEN"]}POST / HTTP/1.1
User-Agent: curl/7.29.0
Host: localhost:8080
Accept: */*
Content-Type: application/json
Content-Length: 58
{"hoge":["2019-07-09 04:44:18","/a/","test.txt","ATTRIB"]}POST / HTTP/1.1
User-Agent: curl/7.29.0
Host: localhost:8080
Accept: */*
Content-Type: application/json
Content-Length: 69
{"hoge":["2019-07-09 04:44:18","/a/","test.txt","CLOSE_WRITE,CLOSE"]}
監視の結果を http で投げられました。
フィルタとか
-
inotifywait
自体にもイベントのフィルタあるし、 -
jq
でフィルタしてもいいし、
そのあたりはお好みで。
ここまで書いて気付いたけど、 ファイルに落として fluentd
でもいけますねこれ。
っていうかそっちの方が良いと思う(今更
おわり。