block_given?

ジャングル ブロック ナイ アルノハ jump ダケ。CC-BY-SA 3.0

インしたお! マイクラ開始即通知、idobata + fluentd

やりたいこと

  • Minecraftのログイン通知をidobataにpostする
  • Minecraftのログアウト通知をidobataにpostする

TL;DR

Minecraftサーバーにfluentdをいれて以下のような設定ファイルでログイン/ログアウト通知を実装した。

<source>
  type tail
  path /home/blockgiven/minecraft/logs/latest.log
  format /^\[(?<time>.*)\]\s\[(?<caused_at>[^/]*)/(?<level>.*)\]:\s(?<log>.*)$/
  time_format %H:%M:%S
  tag minecraft.log
  pos_file /home/blockgiven/fluent/pos/minecraft.pos
</source>
<match minecraft.log.talk>
  type record_reformer
  tag reformed.${tag}
  player ${log.match(/^<(?<player>.*)>\s.*$/)[:player]}
  message ${log.match(/^<(?<player>.*)>\s(?<message>.*)$/)[:message]}
</match>
<match minecraft.log.join>
  type record_reformer
  tag reformed.${tag}
  player ${log.match(/^(?<player>.*)\sjoined\sthe\sgame$/)[:player]}
</match>
<match minecraft.log.left>
  type record_reformer
  tag reformed.${tag}
  player ${log.match(/^(?<player>.*)\sleft\sthe\sgame$/)[:player]}
</match>
<match minecraft.log>
  type rewrite_tag_filter
  rewriterule1 log ^\<.*\>\s.*$ minecraft.log.talk
  rewriterule2 log ^.*\sjoined\sthe\sgame$ minecraft.log.join
  rewriterule3 log ^.*\sleft\sthe\sgame$ minecraft.log.left
</match>
<match debug.**>
  type stdout
</match>
<match reformed.minecraft.log.join>
  type copy
  <store>
    type idobata
    webhook_url https://idobata.io/hook/generic/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    message_template @all <%= record['player'] %>がマイクラはじめたみたい
  </store>
</match>
<match reformed.minecraft.log.left>
  type copy
  <store>
    type idobata
    webhook_url https://idobata.io/hook/generic/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    message_template @all <%= record['player'] %>がマイクラおわったみたい
  </store>
</match>

今まで

定期的に外部からMinecraftサーバーに接続し、ログインを検知するプログラムを、Heroku上で実行していた。

blockgiven/minecraft_logged_in_notifier

このプログラムの利点は、Minecraftサーバーのログファイルを見る権利がなくても、サーバーのIPアドレス/ポート番号さえわかれば動くこと。 今回、サーバーへのアクセス権をゲットしたので、ログファイルを監視する方式に切り替えたい。

Fluentdを導入する

aptで導入

debパッケージからFluentdをインストールする | Fluentdを参考に導入する。

$ sudo apt-get install -y curl
$ curl -L http://toolbelt.treasuredata.com/sh/install-debian-wheezy-td-agent2.sh | sh

う、ログファイルは見れるがsudo権限がなかった。つらい。

gemで導入

幸いgemをいれる権限はある。Ruby GemからFluentdをインストールする | Fluentdを参考にgemとして導入する。

$ gem install fluentd --no-ri --no-rdoc
$ fluentd --setup ./fluent

Minecraftのログからイベントを収集する

設定ファイルはminecraftのログをIRCに流すfluentdのコンフィグを参考にする

<source>
  type tail
  path /home/blockgiven/minecraft/logs/latest.log
  format /^\[(?<time>.*)\]\s\[(?<caused_at>[^/]*)/(?<level>.*)\]:\s(?<log>.*)$/
  time_format %H:%M:%S
  tag debug.minecraft.log
  pos_file /home/blockgiven/fluent/pos/minecraft.pos
</source>
<match debug.**>
  type stdout
</match>

debug.〜でタグ付けするとstdoutに出て便利。 起動は

$ fluentd -c ./fluent/fluent.conf -vv &

設定ファイルの再読み込みはSIGHUPを送る。 pidファイルを作る設定後で確認したい。

$ ps aux | grep fluentd
$ kill -HUP 19955

マインクラフトでログインしてログアウトしログを確認する

2014-11-08 10:37:00 +0900 debug.minecraft.log: {"caused_at":"User Authenticator #9","level":"INFO","log":"UUID of player blockgiven is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}
2014-11-08 10:37:00 +0900 debug.minecraft.log: {"caused_at":"Server thread","level":"INFO","log":"blockgiven[/xxx.xxx.xxx.xxx:xxxxx] logged in with entity id 625953 at (241.04323755057334, 70.0, 124.74428504286337)"}
2014-11-08 10:37:00 +0900 debug.minecraft.log: {"caused_at":"Server thread","level":"INFO","log":"blockgiven joined the game"}
2014-11-08 10:37:11 +0900 debug.minecraft.log: {"caused_at":"Server thread","level":"INFO","log":"blockgiven lost connection: TextComponent{text='Disconnected', siblings=[], style=Style{hasParent=false, color=null, bold=null, italic=null, underlined=null, obfuscated=null, clickEvent=null, hoverEvent=null, insertion=null}}"}
2014-11-08 10:37:11 +0900 debug.minecraft.log: {"caused_at":"Server thread","level":"INFO","log":"blockgiven left the game"}

収集できてる。

次はrewriteの設定をして、ログイン/ログアウト/チャットのログを振り分ける。 rewrite tag filterのプラグインを入れる。

$ gem install fluent-plugin-rewrite-tag-filter

設定を追加する。

<source>
  type tail
  path /home/blockgiven/minecraft/logs/latest.log
  format /^\[(?<time>.*)\]\s\[(?<caused_at>[^/]*)/(?<level>.*)\]:\s(?<log>.*)$/
  time_format %H:%M:%S
  tag minecraft.log
  pos_file /home/blockgiven/fluent/pos/minecraft.pos
</source>
<match minecraft.log>
  type rewrite_tag_filter
  rewriterule1 log ^\<.*\>\s.*$ minecraft.log.talk
  rewriterule2 log ^.*\sjoined\sthe\sgame$ minecraft.log.join
  rewriterule3 log ^.*\sleft\sthe\sgame$ minecraft.log.left
</match>
# rewrite tag filterをいれたので、設定が終わるまで`minecraft.*`を`debug.minecraft.*`にリダイレクト
<match minecraft.log.**>
  type rewrite_tag_filter
  rewriterule1 log . debug.${tag}
</match>
<match debug.**>
  type stdout
</match>

再度読み込んでみる

$ ps aux | grep fluentd
$ kill -HUP 19955

うまくいったようだ

2014-11-08 11:11:02 +0900 debug.minecraft.log.join: {"caused_at":"Server thread","level":"INFO","log":"blockgiven joined the game"}
2014-11-08 11:11:09 +0900 debug.minecraft.log.talk: {"caused_at":"Server thread","level":"INFO","log":"<blockgiven> a"}
2014-11-08 11:11:12 +0900 debug.minecraft.log.left: {"caused_at":"Server thread","level":"INFO","log":"blockgiven left the game"}

誰が出た/入ったのかも切り取りたい。

$ gem install fluent-plugin-record-reformer

debug.をつけるrewriteの設定の前に追加

<match minecraft.log.talk>
  type record_reformer
  tag reformed.${tag}

  player  ${log.match(/^<(?<player>.*)>\s(?<message>.*)$/)[:player]}
  message ${log.match(/^<(?<player>.*)>\s(?<message>.*)$/)[:message]}
</match>
<match minecraft.log.join>
  type record_reformer
  tag reformed.${tag}

  player ${log.match(/^(?<player>.*)\sjoined\sthe\sgame$/)[:player]}
</match>
<match minecraft.log.left>
  type record_reformer
  tag reformed.${tag}

  player ${log.match(/^(?<player>.*)\sleft\sthe\sgame$/)[:player]}
</match>

デバッグの書き換えの後ろにもつけてやる。

<match reformed.minecraft.log.**>
  type rewrite_tag_filter
  rewriterule1 log . debug.${tag}
</match>

うまく動いているようだ

2014-11-08 11:53:59 +0900 debug.reformed.minecraft.log.join: {"caused_at":"Server thread","level":"INFO","log":"blockgiven joined the game","player":"blockgiven"}
2014-11-08 11:54:06 +0900 debug.reformed.minecraft.log.talk: {"caused_at":"Server thread","level":"INFO","log":"<blockgiven> hi","player":"blockgiven","message":"hi"}
2014-11-08 11:54:08 +0900 debug.reformed.minecraft.log.left: {"caused_at":"Server thread","level":"INFO","log":"blockgiven left the game","player":"blockgiven"}

通知する

今回はidobata.ioになげたい。

$ gem install fluent-plugin-idobata
<match reformed.minecraft.log.join>
  type copy
  <store>
    type idobata
    webhook_url          https://idobata.io/hook/generic/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    message_template     @all <%= record['player'] %>がマイクラはじめたみたい
  </store>
</match>
<match reformed.minecraft.log.left>
  type copy
  <store>
    type idobata
    webhook_url          https://idobata.io/hook/generic/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    message_template     @all <%= record['player'] %>がマイクラおわったみたい
  </store>
</match>

はまったところ

reformで書き換えて同じkeyにdestすると無限ループで死ぬ。

まとめ

マイクラにログイン/ログアウトすると即座にidobata.ioに通知されるようになった。 これまで以上にマイクラをやる頻度があがりそう。

fluentdとidobata.io超便利。

  • 今回は設定を1ファイルにべた書きした。分割方法を調べたい。
  • ログファイルを見れない場合も監視できるようにする
  • MinecraftにRubotyを住ませる