tukaのブログ

気が向いた時に何か書きます

Mackerelのカスタムダッシュボードにアラートの一覧を表示する

このエントリはMackerel Advent Calendar 2022の24日目の記事です。

本エントリでは、MackerelのAPIを使ってカスタムダッシュボードに欲しいけど『ない』機能を補う代替機能のアイデアを紹介したいと思います。

TL;DR

  • Mackerel API, mkr, jq を使って、カスタムダッシュボードにアラート一覧を実装する方法を紹介します。
  • 主にシェル芸です。

カスタムダッシュボードのご紹介

Mackerelには、監視の運用に合わせたオリジナルのダッシュボードが実装できるカスタムダッシュボードがあります。

mackerel.io

カスタムダッシュボードには以下の4種類のウィジェットが用意されているので、これらを組み合わせることでより自由度の高いダッシュボードを構成できます。

この4つのウィジェットだけでもダッシュボードを構成するのに充分ですが、ここにはないウィジェットで、次のようなウィジェットのご要望をよくいただきます。

どちらも2022年時点では対応していないのですが、アラートの一覧についてはMarkdownウィジェットで代用できそうなので、実装してみることにしました。

実装していく

この記事では主にLinux環境で動かすことを想定して、bashで実装します。他の環境、言語でももちろん実装できるので参考になればと思います。

必要なもの

bashcurl以外に以下を事前にインストールしてください。

mkrのインストールはヘルプの手順が参考になります。

mackerel.io

ダッシュボードを取得する

アラート一覧を表示したいダッシュボードを取得します。

あらかじめダッシュボードには、アラート一覧用のMarkdownウィジェットを登録しておいてください。

ダッシュボードの取得は、ダッシュボード取得API、mkrのどちらでもできます。

mkr dashboards pull

mkrの場合、カレントディレクトリにdashboards-<ダッシュボードID>.jsonが保存されます。ただ今回はローカルにファイルを残したくなかったので、curlAPIを叩くようにします。

curl \
-X GET \
-s https://api.mackerelio.com/api/v0/dashboards/${DASHBOARD_ID} \
-H "Content-Type: application/json" \
-H "X-Api-Key: ${API_KEY}" \
-f

ダッシュボードの構成に合わせて、次のようなJSONがレスポンスされます。

{
    "id": "xxxxxxxxxxx",
    "title": "毎日見たいダッシュボード",
    "urlPath": "xxxxxxxxxxx",
    "createdAt": 1234567890,
    "updatedAt": 1234567890,
    "memo": "",
    "widgets": [
        {
            "type": "markdown",
            "title": "直近のアラート",
            "layout": {
                "x": 0,
                "y": 0,
                "width": 12,
                "height": 6
            },
            "metric": null,
            "graph": null,
            "range": null,
            "markdown": "ここにアラートの一覧を表示する。"
        },
        {
            "type": "markdown",
            "title": "別のMarkdownウィジェット",
            "layout": {
                "x": 12,
                "y": 0,
                "width": 12,
                "height": 6
            },
            "metric": null,
            "graph": null,
            "range": null,
            "markdown": "こっちは更新されたくない。"
        }
    ]
}

このダッシュボードには2つのMarkdownウィジェットが登録されていて、今回は「直近のアラート」というタイトルがつけられた方のウィジェットに対してアラート一覧を反映します。

ちなみにダッシュボードにはユニークに払い出されたIDを持ちますが、ウィジェットにはIDが払い出されません。そのため、ウィジェットtitleをキーとして使用します。

アラートの一覧を取得する

現在オープンしているアクティブなアラートを取得します。

アラートの取得はアラート取得APIからできますが、 mkr を使うと次のような感じでいい感じにフォーマットされた内容が取得できます。

mkr alerts list
4Hrxxxxxx79 2022-12-07 03:10:32 CRITICAL  死活監視 IP-xxxxxxxx working [Service:Role]
4HrxxxxxxX3 2022-12-07 02:55:24 WARNING  Service - Windows - CPU % cpu% 0.00 > 70.00 IP-xxxxxxxx working [Service:Role]
4HaxxxxxxSm 2022-12-01 14:47:30 CRITICAL  Event Log CRITICAL: 0 warnings, 1 criticals. EC2AMAZ-xxxxxxx working [Service:Role]

アラートID、発生日時、アラートレベル、メッセージなどが含まれるので、今回はこれをそのまま使用します。

この結果をもとに、次のようにMarkdownでリスト化して各アイテムにアラートへのリンクを貼ることで、ダッシュボードからアラートを開けるので便利になりそうです。

- [アラートの情報](アラートへのリンク)
- [アラートの情報](アラートへのリンク)
 :

mkr alerts listの結果のうち、アラートIDはリンクに、それ以外をアラート情報として一覧に表示する形式にしたいですが、awkを使うことで簡単に整形できます。

mkr alerts list | awk '{m="";for(i=2;i<=NF;i++) m=m $i " "; print "- [" m "](https://mackerel.io/orgs/オーガニゼーション名/alerts/" $1 ")"}'
- [2022-12-07 03:10:32 CRITICAL  死活監視 IP-xxxxxxxx working [Service:Role] ](https://mackerel.io/orgs/xxx/alerts/4Hrxxxxxx79)
- [2022-12-07 02:55:24 WARNING  Service - Windows - CPU % cpu% 0.00 > 70.00 IP-xxxxxxxx working [Service:Role] ](https://mackerel.io/orgs/xxx/alerts/4HrxxxxxxX3)
- [2022-12-01 14:47:30 CRITICAL  Event Log CRITICAL: 0 warnings, 1 criticals. EC2AMAZ-xxxxxxx working [Service:Role] ](https://mackerel.io/orgs/xxx/alerts/4HaxxxxxxSm)

この結果をMarkdownウィジェットに反映していきましょう!

ダッシュボードを更新する

取得したダッシュボードのJSONのうち、以下の条件にあてはまる要素の内容を生成したアラート一覧の内容で書き換えます。

  • typemarkdown
  • title直近のアラート

ここで役に立つのがjqです。次のように|=で代入することで内容を書き換えることができます。

jq '(.widgets[] | select(.type == "markdown" and .title == "直近のアラート") | .markdown) |= "整形されたアラート一覧のMarkdown"'`

これをダッシュボード更新APIから定期的に更新することで、カスタムダッシュボードにアラート一覧を表示できます。

完成したスクリプト

これらを組み合わせたBashスクリプトが次のようになります。

#!/bin/bash

API_KEY=APIキー
ORG_NAME=オーガニゼーション名
DASHBOARD_ID=ダッシュボードID
WIDGETS_TITLE=直近のアラート

result=0

# ダッシュボードの取得
DASHBOARD_JSON=$( \
  curl \
    -X GET \
    -s https://api.mackerelio.com/api/v0/dashboards/${DASHBOARD_ID} \
    -H "Content-Type: application/json" \
    -H "X-Api-Key: ${API_KEY}" \
    -f \
) || result=$?

if [ "$result" -ne 0 ]; then
  echo "failed to retrieve dashboard."
  exit 1
fi

# アラート一覧の取得
ALERT_LIST=$( \
  mkr alerts list | \
  awk \
    -v ORG_NAME=${ORG_NAME} \
    '{m="";for(i=2;i<=NF;i++) m=m $i " "; print "- [" m "](https://mackerel.io/orgs/" ORG_NAME "/alerts/" $1 ")"}' \
) || result=$?

if [ "$result" -ne 0 ]; then
  echo "failed to retrieve the alert list."
  exit 1
fi

# アラート一覧のMarkdownウィジェットを修正
MODIFIED_JSON=$( \
  echo $DASHBOARD_JSON | \
  jq -c \
    --arg ALERT_LIST "$ALERT_LIST" \
    --arg WIDGETS_TITLE "$WIDGETS_TITLE" \
    '(.widgets[] | select(.type == "markdown" and .title == $WIDGETS_TITLE) | .markdown) |= $ALERT_LIST' \
) || result=$?

if [ "$result" -ne 0 ]; then
  echo "failed to correct dashboard."
  exit 1
fi

# ダッシュボードの更新
curl \
  -X PUT \
  -s https://api.mackerelio.com/api/v0/dashboards/${DASHBOARD_ID} \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: ${API_KEY}" \
  -d "${MODIFIED_JSON}" \
  -f \
  > /dev/null 2>&1 \
|| result=$?

if [ "$result" -ne 0 ]; then
  echo "failed to update dashboard."
  exit 1
fi

API_KEY, ORG_NAME, DASHBOARD_ID, WIDGETS_TITLE は環境に応じて設定してください。

これをcronで定期的に実行することで、最新のアラート一覧をこんな感じでダッシュボード上に反映できるようになるはずです!

まとめ

いかがでしたでしょうか。

今回は主にLinux環境を想定してシェルで実装していますが、Windows環境だとPowerShellで実装したり、AWS Lambdaなどサーバーレスな環境でも実装することができると思います。

イデア次第で色々と拡張できるので、ぜひ色々と試してみてください!

明日はアドベントカレンダー最終日、id:wtatsuruさんです!お楽しみに!