ちなみに

火曜日の空は僕を押しつぶした。

Mackerel で MacBook のバッテリー残量を記録する話

photo by Thomas Hawk

Mackerel のフリートライアルが終わってしまったという通知が来て、あちゃーと思ったのだけれど無料分でも遊べそうだったので、手元の MacBook Pro 15inch Retina で試してみることにした。

開発機のロードアベレージとか見てもおもしろくもなんともないので、バッテリの残量を記録するようにしてみた。

準備

最初は普通に clone してきてビルドしたものを使おうとしていたけれど、公式で HomeBrew 用のパッケージが提供されていたのでこちらを使うことに。

tap してインストールするだけなので簡単。しかし、公式にはサポートされていないので自己責任で。

$ brew tap mackerelio/mackerel-agent
$ brew install mackerel-agent

起動する前に API キーの設定をしておく。 HomeBrew でインストールした場合は以下に設定ファイルが出来ているので、これを編集するといい。

$ vim /usr/local/etc/mackerel-agent.conf

API キーはオーガニゼーションの詳細ページで確認出来る。 https://mackerel.io/orgs/ORGANIZATION_NAME みたいな URL にアクセスして下部にある API キーをコピーしておく。 設定は TOML 形式になっているので、適当な位置に追加すれば大丈夫。

apikey = "YOUR API KEY"

勝手に立ち上がって欲しいのでインストール後の案内に従って launchd に登録する。

$ ln -sfv /usr/local/opt/mackerel-agent/homebrew.mxcl.mackerel-agent.plist ~/Library/LaunchAgent
$ launchctl load ~/Library/LaunchAgents/homebrew.mxcl.mackerel-agent.plist

起動と終了は以下のように。設定ファイルを書き換えたりしつつ適宜再起動する。

$ launchctl stop homebrew.mxcl.mackerel-agent
$ launchctl start homebrew.mxcl.mackerel-agent

これでしばらく待っていると、標準で取得されるメトリックが記録され始める。 loadavg5cpumemoryinterfacefilesystem の5つが取得出来る。

memory が「データを読み込んでいます」の状態から更新されないのだけれど、サポート外ということを思い出して今回は諦める。

f:id:Sixeight:20150325073240p:plain

ちなみに、各ホストは id と呼ばれるファイルに記録されている hostID によって識別される。 借りてる Linux なんかで業者に頼んでシステムまるごとコピーした場合なんかは注意が必要。

この id ファイルは設定ファイルで root に指定したディレクトリに生成される。 launchd とかなら ~/Library/LaunchAgent に出来てしまうので分かりやすい場所を別途指定すると良さそう。

バッテリー残量を計測する

MacBook のバッテリ残量は pmset というコマンドを使って取得することが出来る。

$ pmset -g ps
Now drawing from 'Battery Power'
 -InternalBattery-0 70%; discharging; 3:28 remaining

現在は 70% 残ってて、電源アダプタをつないでなくて、あと3時間28分くらい使えるということが分かる。 この 70 の部分を抜き出して Mackerel に送ってやればよい。

$ pmset -g ps | tail -n1 | awk '{print $2}' | sed 's/%;//'

みたいな感じで切り出せるけれど、今回は pmset の値を Ruby で加工するようにした。 (最初Perlで書いてたんだけれど、出力は同じように見えるのにどうしてもダッシュボードに追加されなかった。きっと何か間違ってた。)

ところで、mackerel-agent にはプラグインの機構があり、今回はこれを使う。

設定ファイルに以下のように書くと簡単にメトリックを追加出来る。Ruby とかで書けるのでなんでも出来る。

[plugin.metrics.pmset]
command = "ruby /path/to/pmset-metrics.rb"

ユーザ定義のメトリックについては ヘルプ に詳しく書いてあって、この通りにやれば簡単に好きなメトリックを追加出来る。 前述の通り、僕は Perl で書いてて死ぬほどハマったので、比較のために Ruby で書きなおしたら一発で動いてやっぱり Ruby は最高という感想だった。 (Mac には最初から Ruby がインストールされているので、真面目な話 Ruby で書くのが一番手っ取り早いと思う。)

さて、コードだけれど2つの出力を出せるようにする。

mackerel-agent は起動時に MACKEREL_AGENT_PLUGIN_META という環境変数付きで一度プラグインを実行する。 この時に一行目が # mackerel-agent-pluginJSON を標準出力に表示すると、表示するグラフを設定することが出来る。

それ以降は一定時間毎にプラグインを呼び出してメトリックを計測する。 この時の出力は以下のようなものが想定されている。

メトリックの名前\tメトリックの値\tUNIXタイム

たとえばこんな感じ。

macbook.pmset.ib0\t57\t1427235423

これさえ守っていればなんでも送れるので、あんなことやこんなことなど妄想が広がる。 後はその値が取得出来るのかどうかだけが問題になる。

詳しくは ヘルプ を見てください。

今回はバッテリを取得するものを書いてみた。ほとんどヘルプのコピーだけれど。

if ENV["MACKEREL_AGENT_PLUGIN_META"] == '1'
  require 'json'

  meta = {
    :graphs => {
      "macbook.pmset" => {
        :label   => "Battery",
        :unit    => "percentage",
        :metrics => [
          {
            :name  => "ib0",
            :label => "InternalBattery-0"
          },
        ]
      }
    }
  }

  puts "# mackerel-agent-plugin"
  puts meta.to_json
  exit 0
end


def pmset(*args)
  `pmset #{args.join(" ")}`
end

def current_battery
  binfo = pmset "-g", "ps"
  binfo.match(/\t(\d+)\%/)[1].to_i
end

puts ["macbook.pmset.ib0", current_battery, Time.now.to_i].join("\t")

これをプラグインとして登録して、mackerel-agent を再起動すると、しばらくしたらバッテリの値が記録され始める。

ちなみに、ログファイルは /usr/local/var/log/mackerel-agent.log にあるので、これを見ていると起動時のエラーなんかは見つけられる。

f:id:Sixeight:20150325072125p:plain

やったね。
(これを撮るためにバッテリが減るのを待ってたんだけれど、見てるとなかなか減らない。)