FluentdとGrowthForecastを使って自分の行動をロギング・可視化する

の記事のように、FluentdGrowthForecastを使ったロギングって面白そうだなーと思って自分でもやってみた。

アプリケーション毎のアクティブな時間を取る

まず考えたのはこれ。キーイベント発火回数ほど細かくなくても、「アクティブにしている時間の割合」が取れたらそれはそれで良いかな、と。

1秒ごとにアクティブなアプリを調べてロギングしていく。Mac OS Xにおいてアクティブなアプリケーションを調べるならAppleScriptが簡単。

name of (info for (path to frontmost application))

これだけでアクティブにしているアプリケーション名が取れる。
もしくは

tell application "System Events"
    name the first process whose frontmost is true
end tell

といった形でプロセス名として取ることもできるらしい。以下のように変形することもできる。

tell application "System Events" to name of first process whose frontmost is true

なんにせよAppleScript一行で取れるので、ワンライナーのコマンドで書ける。fluentdのconfigで

<source>
  type exec
  command osascript -e 'name of (info for (path to frontmost application))'
  keys application
  tag application
  run_interval 1s
</source>

のように書けば1秒ごとにAppleScript経由でアクティブなアプリケーション名がemitされる。これをdatacounterで1分ごとに集計。

<match application>
  type datacounter
  count_key application
  count_interval 1m
  aggregate all
  tag counted.apps
  pattern1 iTerm iTerm.app
  pattern2 Emacs Emacs.app
  pattern3 Chrome Google Chrome.app
  pattern4 Twitter Twitter.app
</match>

これで主要なアプリがどれくらいアクティブになっているかがだいたい取れる。ので、そのままgrowthforecastに投げてしまう。

<match counted.apps>
  type growthforecast
  gfapi_url http://gf.*****.my.server/api/
  service sugyan
  section apps
  name_keys iTerm_percentage,Emacs_percentage,Chrome_percentage,Twitter_percentage,unmatched_percentage
</match>


こんなかんじでそれぞれのアプリの単位時間あたりのアクティブ率の変化がグラフで取れて、複合グラフにすると

というかんじで「あぁ、このへんはずっとEmacsで何か書いてて、このへんはずっとTwitter見てるな」とかが分かる。

Emacsの文字入力数を取る

Emacsで色々作業する場合に、どんな言語をどれくらい書いているか…じゃなくても、major-modeごとに集計できたら良いかな、と。
post-self-insert-hookで文字入力した際にhookして非同期プロセスからfluentdに送信する。

(defun my-insert-hook ()
  (start-process "post-fluent" nil "curl" "-X" "POST" "-d" (concat "json={\"mode\":\"" (symbol-name major-mode) "\"}") "localhost:9880/emacs"))
(add-hook 'post-self-insert-hook 'my-insert-hook)

上記のようなelispEmacsの設定に書いておけば、文字が入力されるごとにそのバッファのmajor-mode名がcurlを使ってHTTP経由でemitされる。
start-process関数は非同期にコマンド実行されるので連打していても動作が重くなったりしない。と思う。
fluentdのconfigは

<source>
  type http
</source>

<match emacs>
  type datacounter
  count_key mode
  count_interval 1m
  aggregate all
  tag counted.emacs
  pattern1 perl cperl-mode
  pattern2 ruby ruby-mode
  pattern3 javascript js2-mode
  pattern4 minibuffer minibuffer-inactive-mode
</match> 

<match counted.emacs>
  type growthforecast
  gfapi_url http://gf.*****.my.server/api/
  service sugyan
  section emacs
  name_keys perl_count,ruby_count,javascript_count,minibuffer_count,unmatched_count
</match>

といった感じで、1分間あたりに文字入力が起こった回数をmajor-mode毎に集計してグラフ化できる。

zshの実行コマンドを取る

zshでもシェルコマンド実行前後に処理を挟むことができるので、実行したコマンドで集計したりできる。

function preexec_fluent() {
    curl -X POST -d 'json={"command":"'${1%% *}'"}' localhost:9880/zsh
}
preexec_functions=(preexec_fluent)

のようなものを~/.zshrcに書いておけば、コマンド実行するたびにそのコマンド名がemitされる。(ダブルクォートのエスケープとかあんまり考えていないけど)

<source>
  type http
</source>

<match zsh>
  type datacounter
  count_key command
  count_interval 1m
  aggregate all
  tag counted.zsh
  pattern1 ls ls
  pattern2 cd cd
</match>

<match counted.zsh>
  type growthforecast
  gfapi_url http://gf.*****.my.server/api/
  service sugyan
  section zsh
  name_keys ls_count,cd_count,unmatched_count
</match>

コマンドごとに集計する意味はあまり無いかもしれないけど、特定のコマンドをよく使う、という場合は割合を知ることができて良いかも?
合計値を取れば1分あたりどれくらいzshでコマンド叩いているか、の推移は分かると思う。

その他

ほかに何か面白いデータ取れるかなぁ

Carton環境でのflymakeとperl-completion

cartonを使って<PROJECT ROOT>/local以下にモジュールを入れて、それを使う前提で書いているファイルを編集していると、普通にperl -wcしても依存モジュールを見つけられなくてerrorになってしまうので、flymakeが思うように動いてくれない。
ので、Project::Libsを使ってflymake-perl-initをちょっと変更してやる。

<PROJECT ROOT>/local以下も探索対象にするため、こんなかんじに。

(defun flymake-perl-init ()
  (let* ((temp-file   (flymake-init-create-temp-buffer-copy
                       'flymake-create-temp-inplace))
	 (local-file  (file-relative-name
                       temp-file
                       (file-name-directory buffer-file-name))))
    (list "perl" (list "-MProject::Libs lib_dirs => [qw(local/lib/perl5)]" "-wc" local-file))))

これでflymakeに関しては問題ないのだけど、perl-completionでモジュールを検索したりするときにPATHが通らなくて見つからない。
plcmp-cmd-set-additional-lib-directoryコマンドを呼んで一度PERL5LIBに追加してしまえば届くようになるけど、これはplcmp--PERL5LIB-directories(perl-completionの中でPERL5LIBに設定して使うもの)がどんどん追加されていってしまうので何だか気持ち悪い。


plcmp--PERL5LIB-directoriesを汚さずにProject::Libsから参照できるところのドキュメントを探したりできるようにする方法はあるのかなぁ