こんにちは、Mackerel CREの id:kmuto です。いつもMackerelをご利用いただき、誠にありがとうございます。
早速ですが、皆さんはmkrコマンドを使ったことがありますか? 「mkr」は、MackerelのAPIサーバーと直接情報をやりとりできる、コマンドラインインターフェイス(Linux/Unixのターミナルや、WindowsのコマンドプロンプトおよびPowerShell)向けのツールです。Linuxディストリビューションではaptまたはyumなどのパッケージシステム経由でインストールでき、Windowsではmackerel-agentに同梱されています。
mkrでできることは多岐にわたるのですが、本記事ではmkrを使ってMackerelから情報を取得し、さらにそれをmkr上で加工するテクニックを紹介します。
- JSONとjq
- 例1:オーガニゼーション名や管理名を取得する
- 例2:ホストをIDと名前で一覧する
- 例3:マイクロホストのクラウドサービス情報を表示する
- 例4:特定のURL宛ての外形監視設定を探す
- 例5:発生・解決の時刻も添えてアラートを一覧する
- 例6:メトリックをCSV形式でダウンロードする
- おわりに
JSONとjq
mkrでMackerelのAPIサーバーから取得した情報は、JSON形式のデータになっています。
オーガニゼーションの情報を表示するサブコマンドmkr org
を実行してみましょう($
はプロンプトです。Windows環境の場合、mkrコマンドの実行は"C:\Program Files\Mackerel\mackerel-agent\mkr.exe"
とするか、C:\Program Files\Mackerel\mackerel-agent
をユーザーの環境変数PATH
に追加してください)。
$ mkr org { "name": "mackerel-bizdemo", "displayName": "Mackerel🐟デモ環境" }
JSONはJavaScriptのオブジェクト表記方法をもとにしたテキスト型のデータ交換用フォーマットで、キーと値のペア、配列、数値、文字列、真偽値、nullというシンプルなデータ型からなり、構造化されたデータを扱いやすいことから広く使われています。
mkrで取得するJSONは、Mackerel APIドキュメントに記載されているものに準拠しています。上記の例ではオーガニゼーション名(name
)と管理名(displayName
)それぞれのキー・値のペアが入っていますが、これはAPIドキュメントの「オーガニゼーションの情報を取得」相当です。
小さなJSONデータならこのように目視で構造と情報を追えるものの、構造が複雑になっていくと読むのがたいへんですし、最終的な結果として出力したいのは生のJSONデータではなく、その中の何らかの文字列や数値であることがほとんどです。スプレッドシートに取り込んで見ることを目的としたCSV(カンマ区切り)やTSV(タブ区切り)にしたいこともあるでしょう。
JSONデータを抽出・加工するデファクトスタンダードのツールとして、「jq」があります。jqは、JSONを入力データとし、jqフィルタと呼ぶ一連の命令群で加工して、任意の出力データを生成します。
jqのGo言語向けの実装として「gojq」というライブラリがあります。gojqは完全なjqフィルタ互換ではありませんが、本記事で扱う範囲では問題ありません。mkrはgojqを取り込んでおり、情報取得のサブコマンドに備わった--jq
というオプションでjqフィルタを指定して、取得したJSONデータを直接加工できます。
jqフィルタでできることは幅広いのですが、以降ではその一部を紹介しながらMackerelの情報を加工する例を挙げていきます。
例1:オーガニゼーション名や管理名を取得する
先ほどJSONの例を挙げましたが、そこからオーガニゼーション名や管理名を抽出してみましょう。
$ mkr org --jq ".name" mackerel-bizdemo $ mkr org --jq ".displayName" Mackerel🐟デモ環境
--jq
オプションの後に" "
で囲んで1jqフィルタを記述します。
.
はJSONの入力ストリーム(何も加工していないのでここでは入力データ自体)を表します。.name
はその入力ストリームにあるキーname
の値を抽出します。.displayName
も同様です。簡単ですね。
なお、mkr org
で--jq
オプションがサポートされたのはmkrバージョン0.58.0以降(Windowsではmackerel-agentバージョン0.82.0以降)となります。もしflag provided but not defined: -jq
というエラーになってしまったら、mkrを最新のものに更新してください。
また、オーガニゼーション管理名は、英数字のみの制約があるオーガニゼーションに、日本語を含めた任意の別名を付けられるという便利な機能です。詳細については過去の告知記事をご覧ください。
例2:ホストをIDと名前で一覧する
次はオーガニゼーションに所属するホスト一覧を表示するサブコマンドmkr hosts
を使い、結果を加工してみましょう。
mkr hosts
をそのまま実行した結果の一部を示します。
$ mkr hosts [ { "id": "5ch1Pxwn14b", "name": "2acd3c8ef2f846b4863ba386eb96f407", "status": "working", "roleFullnames": [ "blog-ecs:benchmarker" ], "isRetired": false, "createdAt": "2024-06-29T17:44:05+09:00", "ipAddresses": { ... } }, { "id": "4adupJLoZ4w", "name": "ip-xxx-xxx-xxx-xxx.ap-northeast-1.compute.internal", "status": "working", "roleFullnames": [ "Blog:worker" ], "isRetired": false, "createdAt": "2021-02-14T16:58:48+09:00", "ipAddresses": { ... } }, ... ]
入力データは、個々のホストを配列の各要素とする[]
で囲まれたJSON配列です。ここからホストID(id
)を抽出してみます。
$ mkr hosts --jq ".[]|.id" 5ch1Pxwn14b 4adupJLoZ4w ...
.[]
は入力ストリームの配列の各要素を受け取ります。|
は左側の出力ストリームを右側の入力ストリームとするパイプラインで、ここでは各要素のid
の値を取り出しています。
名前(name
)も取得してみることにします。「,
」を使ってキーの名前を列挙することで、それぞれの対応する値を取得できます。
$ mkr hosts --jq ".[]|.id, .name" 5ch1Pxwn14b 2acd3c8ef2f846b4863ba386eb96f407 4adupJLoZ4w ip-xxx-xxx-xxx-xxx.ap-northeast-1.compute.internal ...
取得はできましたが、すべて改行されてしまってわかりにくい結果になってしまいました。このようなときには、結果を配列にして、それをタブ区切りのTSVにするのがよいでしょう。
# まず配列にして… $ mkr hosts --jq ".[]|[.id, .name]" ["5ch1Pxwn14b","2acd3c8ef2f846b4863ba386eb96f407"] ["4adupJLoZ4w","ip-xxx-xxx-xxx-xxx.ap-northeast-1.compute.internal"] ... # TSV形式で書き出す $ mkr hosts --jq ".[]|[.id, .name]|@tsv" 5ch1Pxwn14b 2acd3c8ef2f846b4863ba386eb96f407 4adupJLoZ4w ip-xxx-xxx-xxx-xxx.ap-northeast-1.compute.internal ...
IDと名前の値を取得している箇所を[ ]
で囲んで配列を作成します。さらにこの配列を@tsv
に渡すことで、タブ区切りで固有の文字エスケープも済ませたテキストが出力されます。
例3:マイクロホストのクラウドサービス情報を表示する
Mackerelはクラウドインテグレーションという機能でAWS、Azure、Google Cloudのマネージドサービスの監視ができますが、各サービスはマイクロホストとしてホスト一覧に掲載されます(VMなどのエージェントインストール可能なホストはスタンダードホストとなります)。
サブコマンドmkr hosts
に-v
オプションを付けると、ホストがスタンダードホストかマイクロホストか、マイクロホストの場合はどのクラウドサービスかも表示されます。
$ mkr hosts -v [ { "id": "5ch1Pxwn14b", "name": "aa42c6a6736f4cdaa336f66abe160841", "size": "micro", ... "meta": { ... "cloud": { "provider": "fargate", "metadata": { ... } ... }, ... } }, { "id": "4adupJLoZ4w", "name": "ip-xxx-xxx-xxx-xxx.ap-northeast-1.compute.internal", "size": "standard", ... "meta": { ... "cloud": { "provider": "ec2", "metadata": { ... } ... }, ... } }, { "id": "4UWnwfGs4pf", "name": "502f1673983a4946830027d057570a1c", "displayName": "bizdemo_ecs_cluster", "size": "micro", ... "meta": { ... "cloud": { "provider": "ecscluster", "metadata": { ... } ... }, ... } }, ... ]
マイクロホストに絞ってホストID、名前、クラウドサービスをTSV形式で出力してみましょう。
$ mkr hosts -v --jq ".[]|select(.size == \"micro\")|[.id, .displayName // .name, .meta.cloud.provider]|@tsv" 5ch1Pxwn14b 2acd3c8ef2f846b4863ba386eb96f407 fargate 4UWnwfGs4pf bizdemo_ecs_cluster ecscluster 3zcUAyh3Ztf bizdemo-rds rds 3zcUAxdWtLL bizdemo-web-alb alb ...
入力のJSON配列に対して、条件に合った要素だけを抽出した配列を作るselect
を通します。条件はsize
が"micro"
(マイクロホスト)である、としました。
また、クラウドインテグレーションで登録されたホストには任意の管理名を付けることができますが(displayName
)、管理名が存在したらそれを、なければもともとのホスト名(name
)を使うために演算子//
を使っています。
クラウドサービスの名前は配列要素のmeta
→cloud
→provider
と構造を掘り下げた値なので、入力ストリームの「.
」をつなぐことで取得しています。
例4:特定のURL宛ての外形監視設定を探す
外形監視を含めた監視ルールの設定は、サブコマンドmkr monitors
で取得できます。
$ mkr monitors [ { "id": "45VuBx47jxS", "name": "custom.alb.host_count.bizdemo-web-tg.healthy", "memo": "ALB配下の有効なWebサーバーが減少している", "type": "host", "metric": "custom.alb.host_count.bizdemo-web-tg.healthy", "operator": "<", "warning": 4, "critical": 2, "duration": 3, "maxCheckAttempts": 2, "scopes": [ "Blog: web-lb" ] }, { "id": "4qePHRTdsUy", "name": "Mackerelブランドサイト監視", "type": "external", "method": "GET", "url": "https://ja.mackerel.io", "maxCheckAttempts": 3, "followRedirect": true, "headers": [ { "name": "Cache-Control", "value": "no-cache" } ] }, ... ]
「mackerel」という文字列を監視対象のURLに含んでいる外形監視の情報を抽出してみましょう。
$ mkr monitors --jq ".[]|select(.type == \"external\" and (.url|contains(\"mackerel\")))|[.id, .name, .url]|@tsv" 4qePHRTdsUy Mackerelブランドサイト監視 https://ja.mackerel.io ...
select
の中では、種類(type
)が外形監視("external"
)であること、関数contains
を使ってURL内に文字列「mackerel」を含むこと、の両方が満たされるAND条件としています。なお、文字列マッチを正規表現で記述したいときには、関数test
やmatch
を利用できます。
例5:発生・解決の時刻も添えてアラートを一覧する
アラートの情報はサブコマンドmkr alerts
で取得できます。解決済みのアラートも含めるには-w
オプションも付けます。
$ mkr alerts -w [ { "id": "5ch7ndiFrJh", "status": "WARNING", "monitorId": "4G6yi55Yo1G", "type": "connectivity", "hostId": "4RXBJ9SQw67", "openedAt": 1719656875 }, { "id": "5chdsug4evS", "status": "OK", "monitorId": "45VugCVZyZw", "type": "host", "hostId": "4adupJLoZ4w", "value": 46.666666666666664, "openedAt": 1719656771, "closedAt": 1719657073 }, { "id": "5chcDEbKP3q", "status": "OK", "monitorId": "4UWnLYZ69x3", "type": "check", "hostId": "4adupJLoZ4w", "message": "CloudWatch Logs OK: 0 messages for pattern /ERROR/", "openedAt": 1719656346, "closedAt": 1719656406 }, ... ]
アラートの発生時刻や解決時刻は「epoch秒」で返されます。これは協定世界時(UTC)1970年1月1日午前0時0分0秒からの経過秒数のことです。
関数strflocaltime
を使うと、epoch秒からローカル時間表記の文字列に変換できます(ローカル時間が日本時間になるかは、OSやユーザーの環境設定に依存します。環境変数TZ
で一時的に切り替えることもできます)。
MackerelのWebコンソールのURL、現在の状態、種類、発生時刻と(解決していれば)解決時刻をTSV形式で並べてみましょう。
$ mkr alerts -w --jq ".[]|[@uri \"https://mackerel.io/my/alerts/\(.id)\", .status, (.openedAt|strflocaltime(\"%Y-%m-%d %H:%M\")), if .closedAt then (.closedAt|strflocaltime(\"%Y-%m-%d %H:%M\")) else \"-\" end]|@tsv" https://mackerel.io/my/alerts/5ch7ndiFrJh WARNING connectivity 2024-06-29 19:27 - https://mackerel.io/my/alerts/5chdsug4evS OK host 2024-06-29 19:26 2024-06-29 19:31 https://mackerel.io/my/alerts/5chcDEbKP3q OK check 2024-06-29 19:19 2024-06-29 19:20 ...
URLの生成にはエスケープ等も良きにはからってくれる@uri
を使いました。構成するURL文字列内には\(.id)
という記法でアラートIDの値を挿入しています。
また、解決時刻(closedAt
)はまだクローズされていないアラートには存在しないため、if〜then〜else〜end
の条件構文を使ってclosedAt
が存在しないときには「-
」を表示するようにしました。
例6:メトリックをCSV形式でダウンロードする
Mackerelに投稿されたメトリック値をCSVでダウンロードしたいというご要望はよくいただきます。sabadashiといったOSSのツールもありますが、ここではmkrを使ってCSVファイルに書き出してみましょう。
サブコマンドmkr metrics
で、指定期間に投稿されたホストメトリックまたはサービスメトリックの値をまとめて取得できます(メトリック名はサブコマンドmkr metric-names
で調べられます)。
取り出し開始・終了の時刻は、前出のepoch秒で指定する必要があります。
現在時刻のepoch秒はLinuxではdate +"%s"
、PowerShellではGet-Date -UFormat "%s"
で調べられますが、やろうと思えば、mkrでも可能です2。以下は日付関数を使ってepoch秒を求める例です。
# 現在時刻のepoch秒を返す(日本時間2024年6月28日12:05:10に実行) $ mkr org -jq "now|floor" 1719543910 # 現在時刻から6時間前のepoch秒を返す $ mkr org -jq "now - 60 * 60 * 6|floor" 1719522310 # 時刻文字列からepoch秒に変換する $ mkr org -jq "\"2024-06-28T12:05:10+0900\"|fromdate" 1719543910
now
は現在時刻のepoch秒を返します。小数点付きの精度で得られますが、MackerelのAPIサーバーが許容するのは整数のみなので、小数点以下を関数floor
で切り捨てています(切り上げならceil
、四捨五入ならround
を使います)。
6時間前のepoch秒を求める例では、簡単な数値演算をjqフィルタ内で実行しています。
また、関数fromdate
を使うと、文字列表記した時刻からそのepoch秒を求められます。
上記で求めたepoch秒を使い、ホストID 4adupJLoZ4wのloadavg5
ホストメトリックを取得して、CSV形式で書き出し(@csv
)をしてみましょう。
# もともと出力されるJSONデータ $ mkr metrics --host 4adupJLoZ4w --name loadavg5 --from 1719522310 --to 1719543910 [ { "time": 1719522360, "value": 0.04 }, { "time": 1719522420, "value": 0.03 }, { "time": 1719522480, "value": 0.04 }, ... { "time": 1719543900, "value": 0.07 } ] # CSV形式での書き出し $ mkr metrics --host 4adupJLoZ4w --name loadavg5 --from 1719522310 --to 1719543910 --jq ".[]|[(.time|strflocaltime(\"%Y-%m-%d %H:%M\")), .value]|@csv" "2024-06-28 06:06",0.04 "2024-06-28 06:07",0.03 "2024-06-28 06:08",0.04 "2024-06-28 06:09",0.05 "2024-06-28 06:10",0.08 ... "2024-06-28 12:05",0.07 # スプレッドシートなどで扱うためにファイルに書き出す $ mkr metrics --host 4adupJLoZ4w --name loadavg5 --from 1719522310 --to 1719543910 --jq ".[]|[(.time|strflocaltime(\"%Y-%m-%d %H:%M\")), .value]|@csv" > 2024-06-28-loadavg5.csv
>
はリダイレクト記号で、その右側に指定した名前のファイル(ここでは2024-06-28-loadavg5.csv
)に書き出します。
なお、Mackerelの制約上、範囲を長くすると取得メトリックの粒度が1分よりも粗くなっていきます。1分粒度で取得したいときには、範囲を20時間以内に収める必要があります。
おまけとして、範囲で取得したメトリックのうち、最大の値を求めてみます。これはmax_by
という関数で簡単に実現できます(最小はご想像のとおりmin_by
です)。
$ mkr metrics --host 4adupJLoZ4w --name loadavg5 --from 1719522310 --to 1719543910 --jq "max_by(.value)|[(.time|strflocaltime(\"%Y-%m-%d %H:%M\")), .value]|@csv" "2024-06-28 09:10",0.58
おわりに
駆け足でしたが、mkrのjqオプションを使ったMackerelの情報加工テクニックを紹介してきました。特にWindows Server環境では、Linux環境に比してOSの標準機能として提供されているフィルタツールが乏しく、PowerShellを使うのも複雑になりがちなので、mkrだけで加工を完結できるのは便利でしょう。
ぜひ皆さんの日々の運用の利便性向上にご活用ください!