Mackerelのグラフをカスタマイズする

この記事は [Mackerel Advent Calendar 2023](https://qiita.com/advent-calendar/2023/mackerel) の 12/12 の記事です。

昨日は @ryuichi1208 さんの「好きなMackerelプラグインTOP5」でした。

https://ryuichi1208.hateblo.jp/entry/2023/12/11/233029

私は Mackerel CRE チームのテクニカルサポート担当の masarasi です。主にユーザーさんからのお問い合わせ対応やドキュメントの更新などを行っています。私からはグラフ定義についてお話しします。

# Mackerel のグラフが表示されるのはグラフ定義という仕組みがあるから

Mackerel は mackerel-agent をインストールしたり、公式プラグインを利用したりすることでさまざまなメトリックを投稿できますが、自分のほしいメトリック自由に投稿することもできます。ここでは詳しく解説しませんが、メトリックを投稿する方法についてはヘルプを公開しています。

https://mackerel.io/ja/docs/entry/advanced/custom-metrics

Mackerel は新たにメトリックが投稿されると、投稿されたメトリック名にあわせて自動的にグラフが作成されます。例として、以下は自作したプラグインを mackerel-agent に設定して、名前に IP アドレスを含む `custom.server.IPアドレス` (例：`custom.server.172_16_1_101` )という名前のメトリックを投稿した際に自動的に作成されたグラフです。

![通常のグラフ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651975/c2fdb340-76d3-fd3e-ceef-315545a07d87.png)

なぜこのようなグラフができあがるのでしょう。それは Mackerel が投稿されたメトリックごとに自動的に「グラフ定義」というものを作成してくれているからです。グラフ定義には以下のルールがあります。


## 名前の最後の `.`（ドット）までが共通するメトリックがひとつのグラフにまとめられる

先ほどのグラフに投稿されたメトリック名に注目してみましょう。

`custom.server.172_16_1_101` 〜 `custom.server.172_16_1_103`
`custom.server.172_16_2_101` 〜 `custom.server.172_16_2_103`

名前に `.` が 2 つ含まれています。グラフ定義のルールにおいてはメトリック名の最後の `.` までが共通するメトリックが 1 つのグラフにまとめられます。上記のメトリックは `custom.server.` までが共通しているので、すべてのメトリックが 1 つのグラフに表示されています。


## グラフの凡例は `.`（ドット） で区切られた最後の文字列になる

先ほどのグラフの凡例には `172_16_1_101` が表示されています。グラフの凡例は投稿されたメトリック名の最後の `.` より後の文字列になります。 

ここでお気づきの方はいるかもしれませんが、IP アドレスのオクテットの区切り文字も `.` なので、たとえば `custom.server.172.16.1.101` のようにそのままメトリック名にすると、最後の `.` より後の文字は第 4 オクテットのみになるため、凡例は `101` になります。また、`custom.server.172.16.1.101` と `custom.server.172.16.2.102` は最後の `.` の手前である第 3 オクテットが共通しないので、グラフは別々のものになります。

それはそれでよいケースもあると思いますが、今回は 1 つのグラフにまとめたかったので、IP アドレスの `.` を `_` に置き換えてメトリック名としています。

まとめると以下のようになります。

- `custom.server.172_16_1_101` と `custom.server.172_16_2_101` は最後の `.` より前の文字列が共通なので同じグラフにまとめられる
- `custom.server.172.16.1.101` と `custom.server.172.16.2.101` は共通する文字列が `custom.server.172.16` までなので別のグラフになる
- `custom.server.172_16_1_101` の場合、凡例は `172_16_1_101` と表示される
- `custom.server.172.16.1.101` の場合、凡例は `101` と表示される

メトリック名は自由に設定可能なので、上記のルールを理解してメトリック名の `.` 区切りの箇所を工夫すれば、グラフの表示のされ方をコントロールできます。


# グラフ定義を使いこなして表示をカスタマイズする

ここまではカスタムメトリックを投稿した際に自動でグラフが表示される仕組みの解説でした。ここからはグラフ定義を使いこなして表示をカスタマイズする方法のご紹介です。

グラフ定義は以下の Mackerel API ドキュメントの [グラフ定義の投稿](https://mackerel.io/ja/api-docs/entry/host-metrics#post-graphdef) によって設定できます。

https://mackerel.io/ja/api-docs/

ここでは以下のグラフの凡例のように、IP アドレスの第 3 オクテットまでをグループ化したグラフを作ってみます。凡例をクリックするとそのメトリックの表示/非表示を切り替えられるのですが、メトリックが多い場合はグループ化しておくとグループごとに非表示にしたり、見た目もすっきりさせたりすることができます。

![グループ化グラフ_凡例一部非表示.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651975/57d64983-9761-d2f1-9f7f-6a16f55df2bc.png)

このグラフに投稿されているメトリックは `custom.server.172_16_1.101` や `custom.server.172_16_2.101` といった名前です。最後の `.` より後の文字列は第 4 オクテットになり、凡例にも `101` が表示されています。

ですが、先ほどご紹介したようにグラフは最後の `.` までが共通するグラフがまとめられるというルールでした。`custom.server.172_16_1` と `custom.server.172_16_２` では共通していないのにどうして？という感じですよね。これを実現する方法があります。

はじめに、このグラフを作成するためのグラフ定義（json）は以下です。

```json
[
  	{
		"name" : "custom.server.#",
		"displayName": "Server",
		"metrics": [
		   { "name": "custom.server.#.*", "displayName": "%1", "isStacked": false }
		]
	}
]
```

ここでは 2 つのテクニックを使用しています。

## `#`（シャープ）でメトリック名の一部をグループ化

`name` にはメトリック名の最後の `.` より前の部分を指定します。ここで `#` を利用すると、メトリック名の `#` にあたる部分の文字列が異なっていても `custom.server` までが共通していれば同じグラフに表示され、`#` の文字列で凡例がグループ化されます。

上記の `custom.server.#` という指定の場合、`custom.server.172_16_1.101` や `custom.server.172_16_2.101` といったメトリック名で `#` にあたるのは `172_16_1` と `172_16_2` ですので、この文字列がグループ化されます。先ほどお見せした画像のグラフどおりですね。

## `*`（ワイルドカード）で不特定多数のメトリック名に対応

```json
"metrics": [
   { "name": "custom.server.#.*", "displayName": "%1", "isStacked": false }
]
  ```

`metrics[]` の `name` には最後の `.` より後も含むメトリック名を指定します（最後の `.` より前の部分は `name` で指定した文字列と同じでなくてはいけません）。投稿するメトリック名があらかじめわかっている場合はそれらすべてを羅列してもよいです。`custom.server.172_16_1.101` や `custom.server.172_16_1.102` のように、第 4 オクテットだけが変動する場合は `*`を使用して一括定義できます。

`displayName` には凡例に表示する文字列を指定します。`%1` を使用すると、`metrics[]` の `name` に含まれる `*` の値を凡例に表示します。

なお、`*` を含むグラフ定義のカスタムメトリックは、一定時間（およそ6〜8時間以上）送信がない場合に自動的に削除されますのでご注意ください。


# グラフ定義を設定する際の注意点

グラフ定義は API による更新や削除に対応していません。グラフ定義の設定はグラフ右上の歯車アイコンもしくはグラフ定義一覧の画面から変更できますが、変更できる項目は一部です。また、グラフ定義の削除はグラフ定義一覧画面からのみ行なえます。

グラフ定義一覧画面はホスト詳細画面の「カスタムメトリック」という見出しの右側にある「設定」からアクセスできます。以下の URL でも直接アクセス可能です。

`https://mackerel.io/orgs/<オーガニゼーション名>/graph-defs`

メトリックの投稿後に API でグラフ定義を作り直す場合は、既存のグラフ定義を削除してから行う必要があります。また、グラフ定義はメトリックが投稿されると自動で作成されるため、メトリックが投稿されない状態にしたうえで行ってください。


# mackerel-agent を利用してグラフ定義を設定する

ここまではグラフ定義の仕組みと API でグラフ定義を設定する方法の解説でした。ここからは mackerel-agent を経由してグラフ定義を設定する方法のご紹介です。

そもそも、新たにメトリックを投稿する際にグラフ定義が自動で作成されるのは mackerel-agent のおかげです。mackerel-agent は起動時に新たに投稿されるカスタムメトリックがあるとグラフ定義を作成し、Mackerel に送信します。公式プラグインにはあらかじめデザインしたグラフ定義を行ってあるので、どなたが利用してもグラフ名や凡例などがほとんど同じグラフができあがります。

自作のプラグインを使ってカスタムメトリックを投稿する際は、事前に API でグラフ定義を行ってからメトリックを投稿してもよいのですが、プラグインにグラフ定義を送信するための処理を加えると、mackerel-agent の起動時にグラフ定義を行うこともできます。

その方法については冒頭でご紹介した「ホストのカスタムメトリックを投稿する」ヘルプの [グラフ定義を指定する]( https://mackerel.io/ja/docs/entry/advanced/custom-metrics#graph-schema) に記載されています。ここでは自作のプラグインで以下のようなドライブごとのディスク使用率のグラフを作成する方法のご紹介です。

![エージェント経由のグラフ定義.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651975/3fd81dba-dbd4-39c7-6ceb-d8fa57b7e17a.png)

プラグインの内容は以下のようになります。[グラフ定義を指定する]( https://mackerel.io/ja/docs/entry/advanced/custom-metrics#graph-schema) には Ruby によるサンプルが記載されていますが、こちらは Bash のサンプルとなります。

```bash
#!/bin/sh

if [ "$MACKEREL_AGENT_PLUGIN_META" = 1 ]; then
json=$(cat << EOS
{
  "graphs": {
    "disk.#": {
      "label": "ディスク使用状況",
      "unit": "percentage",
      "metrics": [
        {
          "name": "*",
          "label": "%1",
          "stacked": true
        }
      ]
    }
  }
}
EOS
)
echo "# mackerel-agent-plugin"
echo $json | jq -c
else
  # メトリックを出力する処理
  # 以下は固定値を投稿するだけのサンプルです。投稿したいメトリックを出力する内容に置き換えてください。
  echo -e "disk.C.total\t100\t`date +%s`"
  echo -e "disk.C.used\t40\t`date +%s`"
  echo -e "disk.C.free\t60\t`date +%s`"
  echo -e "disk.D.total\t100\t`date +%s`"
  echo -e "disk.D.used\t80\t`date +%s`"
  echo -e "disk.D.free\t20\t`date +%s`"
fi
```

ヘルプに記載されているように、mackerel-agent 起動時の `MACKEREL_AGENT_PLUGIN_META` が `1` の場合に、グラフ定義を出力する処理を記述しています。
なお、mackerel-agent はカスタムメトリックの投稿時に自動でメトリック名の先頭に `custom` を付与するため、グラフ定義や出力するメトリック名において `custom` は不要です。

# 最後に

いかがだったでしょうか。本記事がグラフ定義の理解に役立ち、グラフ定義を触ってみようかなという気持ちになっていただけたらうれしいです。


# [PR] Mackerel Meetup #15 Tokyoを2023年12月19日（火）に開催します

「チームとコミュニティで監視を育てる」をテーマに、監視を育てるスタート地点でもあり、考え方でもある「SRE」の概念やその導入方法、具体的な実装について知ることのできるコンテンツを用意しています。Mackerelをお使いの方も、これから使い始めようという方も、明日から自分たちの監視やシステムを育てるヒントにしていただけたら幸いです。ぜひMackerelチームメンバーに会いに来てください！

詳細とご応募はこちらから！

https://mackerelio.connpass.com/event/302254/