)というライブラリを利用しています。sidekiqでは非同期処理用のジョブをRedis上のキューで管理します。このキューにどのくらいの数のジョブが入っているのかという情報をmackerelのカスタムメトリクスとして管理するためのプラグインを書いたのでご紹介します。mackerel-agentはgoで書かれており、その影響か公式のプラグインもgoで書かれています。https://github.com/mackerelio/mackerel-agent-plugins公式ライブラリを幾つか見るとgoの練習にちょうどよさそうな難易度でしたので、goの勉強も兼ねてmackerelプラグインを書いてみることにしました。プラグインを作るのに便利なライブラリたちカスタムメトリクスを投稿する方法はmackerelの公式ヘルプに書いてあります。http://help-ja.mackerel.io/entry/advanced/custom-metricsそれによると、標準出力に以下のフォーマットで1メトリクス1行で出力すればいいそうです。seconds}(\tはタブ文字)また、環境変数MACKEREL_AGENT_PLUGIN_METAが1の時にグラフ定義を出力するようにするとmackerel側がグラフのタイトルや凡例を自動的にセットしてくれるみたいです。mackerel-agent-pluginから始めてその後にグラフ定義本体のJSONを続けます。API仕様のグラフ定義の投稿の部分に書かれています。http://help-ja.mackerel.io/entry/spec/api/v0#graphdef-postこれらの機能を全部自分で実装してしまっても良かったのですが、プラグインを作るためのヘルパーライブラリがmackerel公式から出ていたので、それを利用してプラグインを作ってみました。https://github.com/mackerelio/go-mackerel-pluginまた、goのRedisクライアントとしてredigoを利用しました。https://github.com/garyburd/redigoこれらのライブラリのインストールはgo言語に標準添付されているパッケージマネージャーを利用して行いました。github.com/garyburd/redigo/redisグラフの定義まずはこのプラグインを表す構造体を定義します。Namespace)はRedisに接続するための情報です。詳細についてはRedisに接続をする部分で説明します。次にこの構造体にPluginインターフェースを実装していきます。Pluginインターフェースはgo-mackerel-pluginの中で次のように定義されているインターフェースです。map[string]Graphs}グラフ定義を返すためのメソッドGraphDefinitionと、メトリクスの情報を返すためのメソッドFetchMetricsがあります。最初にGraphDefinitionメソッドを実装してみましょう。このメソッドの返り値はグラフ名とをキーとして、そのグラフの定義(Graphs構造体)をバリューとするmapオブジェクトです。グラフ名はグラフ内の各メトリクス名のプリフィックスになります。Graphs構造体は次のように定義されています。`json:"metrics"`}LabelフィールドでMackerelで表示されるグラフのタイトル(下図)を指定します。Unitフィールドでこのグラフで表示するメトリクスの単位を指定します。UIからグラフの設定を行うときの「単位」に相当します。Metricsでこのグラフに表示するメトリクスの一覧を指定します。Metrics構造体は以下のように定義されています。`json:"scale"`}Nameフィールドはメトリクス名の後ろ半分を示し、Graphs構造体の中のNameと合わせて完全なメトリクス名となります。Labelフィールドはメトリクスの凡例の名前を示します。Diffフィールドはこのメトリクスの値を差分値として扱うか否かを指定します。このフィールドにtrueを指定すると、前回の値との差分が投稿されます。Stackedフィールドはこのメトリクスを積み上げグラフとして表示するか否かを指定します。trueを指定すると積み上げグラフ、falseを指定すると折れ線グラフとして表示されます。Scaleはメトリクスのスケールを指定します。ここに値0以外の値を指定するとFetchMetricsメソッドで取得した値にScaleの値を乗じた値が投稿されます。実際に、Sidekiq用のグラフ定義を作ってみましょう。sidekiqのキューとして、queue1〜queue3があることを想定しています。queue3)を定義しています。それらの値を積み上げグラフとして表示するように指定しています。キューの種類が前もって分かっているのならばこのままでもいいのですが、せっかくなのでキューの種類をRedisから取得し、そこからメトリクスも動的に生成してみましょう。キューの種類はRedisのqueuesにセット型として入っているので、以下のようなメソッドを作ってキューの種類を取得します。ここでs.Targetには接続先のRedisのIPアドレスが、s.Databaseにはsidekiqの情報が入っているDB番号が入っていると想定しています。s.Namespaceにはsidekiqの情報のキーのprefixが入っていると想定しています。)を使用している場合はこのフィールドに値をセットする必要があります。nil}ここからMetricsオブジェクトのsliceを生成するためには以下のような関数を定義しました。nil}これを使用すると、先ほどのGraphDefinitionは以下のように書き換えられます。}}メトリクスの取得メトリクスの値の投稿のためにFetchMetricsメソッドをSidekiqPlugin構造体に実装します。FetchMetricsメソッドは複数のメトリクスを取得してその値をmap[string]float64型で返すメソッドです。返り値のmapのキー名はGraphDefinitionメソッドで指定した名前を指定します。今回のケースではqueue.<キュー名>になります。GraphDefinitionと同様にキューの種類を動的に取得しています。それらのキューごとに、エンキューされているJOBの数を取得してmetricsに格納しています。nil}メイン関数あとは、上記のメソッドにコマンドラインオプションをパースする処理や、MackerelPluginオブジェクトを設定する処理を追加すればプラグインの完成です。接続先のRedisの情報やプラグインが利用する一時ファイルの設定をコマンドラインオプションとして取得できるようにしています。標準出力に対して出力を行う時には環境変数MACKEREL_AGENT_PLUGIN_METAの値をチェックし、グラフ定義の出力か、メトリクスの値の出力かを切り替えています。UIからグラフを見ることができます。/etc/mackerel-agent/mackerel-agent.confに以下の行を追加します。-db=0"その後、mackerel-agentの再起動を行うと設定ファイルが読み込まれ、カスタムメトリクスの投稿が始まります。trueを指定しているので、積み上げグラフとして表示されます。バイナリの配布(おまけ)goはクロスコンパイルが容易なので、クロスコンパイルをしてバイナリを配布してみました。注:mackerel-pluginの作成を行うためにはこの作業は必須ではありません。mackerel-agentはLinuxとWindowsの32/64ビット環境で動作するので、これらの環境のバイナリを作ってみることにします。buildを行えばようです。複数環境のバイナリをコンパイルするシェルスクリプトを自分で書いてもいいですが、クロスコンパイルを簡単に行うためのライブラリであるgoxを利用してみました。gox自身もgoで書かれているので、インストールにはgo標準のパッケージマネージャーを使います。github.com/mitchellh/goxあとは以下のコマンドを叩くだけで複数環境用のバイナリを生成できます。amd64"クロスコンパイル後のバイナリはbintrayに配置し、ダウンロードできるようにします。APIを叩くだけでバイナリのアップロードを行うことができるので、CUIだけで全ての操作を完結させることができて便利です。https://bintray.com/docs/api/#_content_uploading_publishingまとめわずか200行足らずのコードでmackerelのカスタムメトリクスの投稿ができました。tutorialを終えた直後にやると丁度良いくらいの難易度なので、goの練習問題としても最適だと思います。ユニットテストをもう少し充実させたら公式のプラグイン集にたいしてPRを投げてみたいと思います。