Prometheus の JSON を jq で処理する
Prometheus の JSON を jq で処理する
気付き
この作業で得られた気付きを先に書いておく
- 更新代入
|=
についての誤解- jq コマンドのパイプ文字
|
はunixシェルのパイプ文字とは若干イメージが異なる |=
は独立のオペレーターで、2つの演算子|
と=
を組み合わせたものではない- 下記の例でも
.data.result[].values[] | .[0] |= strflocaltime("%Y-%m-%dT%H:%M:%S%z")
- これだとvalues[]の2つの要素が出てくる。
.[0]
のフィルターではなく、|=
の結果が出力となる
- これだとvalues[]の2つの要素が出てくる。
.data.result[].values[] | .[0] | . = strflocaltime("%Y-%m-%dT%H:%M:%S%z")
- これだとvalues[]の最初の要素しか出てこない。
.[0]
のフィルターがかかる。
- これだとvalues[]の最初の要素しか出てこない。
- 下記の例でも
- jq コマンドのパイプ文字
- フィルターをまとめるにはカッコ
()
を使う - JSONで少し離れた場所の情報は変数に持つ
やりたいこと
(*): https://prometheus.io/docs/prometheus/latest/querying/functions/#increase
The increase is extrapolated to cover the full time range as specified in the range vector selector, so that it is possible to get a non-integer result even if a counter increases only by integer increments.
入力
HTTP API /api/v1/query_range の結果がこんなだったとして
{ "status" : "success", "data" : { "resultType" : "matrix", "result" : [ { "metric" : { "__name__" : "foo", "job" : "node", "instance" : "bar:9100" }, "values" : [ [ 1689329940, "1.000023" ], [ 1689329955, "4.000056" ], [ 1689329970, "7.000089" ] ] }, { "metric" : { "__name__" : "foo", "job" : "node", "instance" : "baz:9100" }, "values" : [ [ 1689329940, "1.000023" ], [ 1689329955, "4.000056" ], [ 1689329970, "7.000089" ] ] } ] } }
unix time変換
unix timeを変換。iso8601拡張形式にしようとしたが、微妙に間違っている(タイムゾーンにコロン :
がない)。
.data.result[].values[] | .[0] | strflocaltime("%Y-%m-%dT%H:%M:%S%z")
結果
2023-07-14T10:19:00+0000 2023-07-14T10:19:15+0000 2023-07-14T10:19:30+0000 2023-07-14T10:19:00+0000 2023-07-14T10:19:15+0000 2023-07-14T10:19:30+0000
無理やりコロンを挿入。jq の sub() の正規表現で、後方参照は名前付きキャプチャー((?<name>pattern)
)というものを使って、 "\(.name)"
のように参照するそうだ。
.data.result[].values[] | .[0] | strflocaltime("%Y-%m-%dT%H:%M:%S%z") | gsub("(?<a>[+-][0-9][0-9])(?<b>[0-9][0-9])"; "\(.a):\(.b)")
結果
2023-07-14T10:19:00+00:00 2023-07-14T10:19:15+00:00 2023-07-14T10:19:30+00:00 2023-07-14T10:19:00+00:00 2023-07-14T10:19:15+00:00 2023-07-14T10:19:30+00:00
少数を整数に丸め
ダブルクォーテーションが付いているので、数値型にしてから整数にする
.data.result[].values[] | .[1] | tonumber | round
結果
1 4 7 1 4 7
instance を出力する
これは変数に覚えておく
.data.result[] | .metric.instance as $instance | $instance
結果
bar:9100 baz:9100
処理をまとめる
- jqの場合、これが意外に面倒になる。今回は更新代入
|=
を繰り返せば良かったので、比較的、単純 - strflocaltimeとgsubをカッコでまとめてから代入する
- tonumberとroundもカッコでくくる
- 最後に配列にしてCSVにする
(雰囲気で、改行してインデントしてみたけど、何か整形ルールはあるのかな)
.data.result[] | .metric.instance as $instance | .values[] | .[0] |= (strflocaltime("%Y-%m-%dT%H:%M:%S%z") | gsub("(?<a>[+-][0-9][0-9])(?<b>[0-9][0-9])"; "\(.a):\(.b)")) | .[1] |= (tonumber | round) | [.[0], $instance, .[1]] | @csv
結果
"2023-07-14T10:19:00+00:00","bar:9100",1 "2023-07-14T10:19:15+00:00","bar:9100",4 "2023-07-14T10:19:30+00:00","bar:9100",7 "2023-07-14T10:19:00+00:00","baz:9100",1 "2023-07-14T10:19:15+00:00","baz:9100",4 "2023-07-14T10:19:30+00:00","baz:9100",7
お試しURL
これはいつまで有効なんだろう?