MacのキーボードやマウスのログをKibanaで可視化する


MacにKibanaとtd-agentをインストールするの続き。

Kibanaとか使ってみたいとは思ってるんだけど、流し込むログなんて無いし…と思っている人に贈る。

自分のパソコンのイベントログなら手元だけで完結するし、ログの量もそれなりにあって、データとしてもおもしろい。

キーボードやマウスのログをsyslogに出すデーモンを作る

↓こういう50行ぐらいのプログラムを作った。

CGEventなんちゃらというのがMacの色々なイベントのコールバックを設定するインターフェイスで、aslなんちゃらというのがMacにおけるsyslogのラッパー。

これでコンパイルできる。

$ clang macbooklog.m -o macbooklog -framework Cocoa

または、リポジトリMakefile を置いてあるので、

$ make

で良い。

キーボードのログを取得するにはこれをrootで実行しないといけない。 (マウスだけならroot必要なし)

デーモンとして起動しておいてほしいので、plistを設置。

$ sudo cp macbooklog /usr/sbin/macbooklog
$ sudo cp macbooklog.plist /Library/LaunchDaemons/

デーモンを起動。

$ sudo launchctl load /Library/LaunchDaemons/macbooklog.plist

これで /var/log/system.log をtailすればログが見られる。

キーコードも取得するには

リポジトリのコードのままではキーボードのイベントだけを出すようにしてて、キーコードをログに含めていない。含める場合はよしなにコメントを外したりすれば良いのだけど、キーログ出してるとパスワードを他人に知られる可能性があるので自己責任でやってね。

syslog (ASL) の設定

上のままでも普通のsyslogにログが流れてくるが、1つ困ったことがあって、20秒以内に同じログがあった場合は

--- last message repeated 17 times ---

のようになってしまうらしい。(coalesceされるというらしい)

syslogの設定で、macbooklogの場合だけcoalesceをオフにしてついでに別のログファイルに出すようにしておこう。fluentdの設定でもそっちだけをtailすればいいので余計な処理しなくて良さそう。

ASLはsyslogのラッパー。/etc/syslog.conf とは別に /etc/asl.conf というのがある。両方使えるらしいが、asl.confのほうに設定がいくつか書いてあるのでそっちを使う。asl.confではログローテートの設定ができるのが便利。

/etc/asl.conf 自体に書いてしまうとOSのアップデートで上書きされる可能性があるため、 /etc/asl/macbooklog に↓のファイルを置く。

# write macbooklog's log to macbooklog.log and do not coalesce
? [= Facility macbooklog] claim only
* file /var/log/macbooklog.log file_max=1M all_max=5M coalesce=false

macbooklogのログは /var/log/macbooklog.log というファイルにかかれて、1MBごとにログローテートされて、全部で5MBになったら古いものから消される。coalesceはしないという意味。

あとはsyslogdを再起動。

$ sudo launchctl stop com.apple.syslogd
$ sudo launchctl start com.apple.syslogd

/var/log/macbooklog.log を見てみるとこんな感じにログが出ているはず。

Sep  6 10:25:32 Atsushis-MacBook-Pro.local macbooklog[22757] <Notice>: kCGEventKey:3
Sep  6 10:25:33 Atsushis-MacBook-Pro.local macbooklog[22757] <Notice>: kCGEventKey:36
Sep  6 10:25:33 Atsushis-MacBook-Pro.local macbooklog[22757] <Notice>: kCGEventMouseMoved
Sep  6 10:25:33 Atsushis-MacBook-Pro.local macbooklog[22757] <Notice>: kCGEventMouseMoved
Sep  6 10:25:33 Atsushis-MacBook-Pro.local macbooklog[22757] <Notice>: kCGEventMouseMoved

簡単にインストールできるようにした

ここまでのことを make install でやってくれるようにした。

$ sudo make install
cp macbooklog /usr/sbin/macbooklog
cp macbooklog.plist /Library/LaunchDaemons/macbooklog.plist
launchctl load /Library/LaunchDaemons/macbooklog.plist
launchctl stop macbooklog
launchctl start macbooklog
cp macbooklog.asl.conf /etc/asl/macbooklog
launchctl stop com.apple.syslogd
launchctl start com.apple.syslogd

アンインストールは make uninstall

$ sudo make uninstall
rm /usr/sbin/macbooklog
launchctl unload /Library/LaunchDaemons/macbooklog.plist
rm /Library/LaunchDaemons/macbooklog.plist
rm /etc/asl/macbooklog
launchctl stop com.apple.syslogd
launchctl start com.apple.syslogd

fluentdでsyslogを読む

td-agentを使っているので、/etc/td-agent/td-agent.conf に以下のように書くと、syslogが読める。

<source>
  type tail
  path /var/log/macbooklog.log
  pos_file /tmp/macbooklog.pos
  tag macbooklog
  format syslog
</source>

ElasticSearchに流すところまで含めると、こうなった。

<source>
  type tail
  path /var/log/macbooklog.log
  pos_file /tmp/macbooklog.pos
  tag macbooklog
  format syslog
</source>

<match macbooklog>
  type rewrite_tag_filter
  rewriterule1 message ^kCGEventKey             macbooklog.key
  rewriterule2 message ^kCGEventScrollWheel$    raw_macbooklog.mouse.scroll
  rewriterule3 message ^kCGEventMouseMoved$     raw_macbooklog.mouse.move
  rewriterule4 message ^kCGEventLeftMouseDown$  macbooklog.mouse.click
  rewriterule5 message ^kCGEventRightMouseDown$ macbooklog.mouse.click
</match>

<match raw_macbooklog.**>
  type sampling_filter
  interval 10
  remove_prefix raw_macbooklog
  add_prefix macbooklog
</match>

<match macbooklog.**>
  type elasticsearch
  host localhost
  port 9200
  logstash_format true
  logstash_prefix macbooklog
  include_tag_key true
  tag_key event
</match>

マウスのログがキーボードに比べてだいぶ多いので、適当にサンプリングしてやる。(上の設定では10分の1)

fluent-plugin-sampling-filterが必要。

sudo /opt/td-agent/embedded/bin/fluent-gem install fluent-plugin-sampling-filter

キーコードもログに含める場合は fluent-plugin-parser を使ってよしなにやる。(リポジトリのREADMEに設定例を書いておいた)

以上

Kibanaのデフォルトのlogstash形式ダッシュボードの設定をいい感じに弄ると、簡単にこういうグラフが作れる。

いつ寝てるのか一目瞭然!

午前中はvimでコードを書いてたのでJKLが多かった。

これだけだとElasticSearchに溜まり続けるので、古いログは消したりしないといけない。https://github.com/elasticsearch/curator を検討してみましょう。