六つのパネルがそれぞれ別の問いに答えていた
目標
欠陥が入ったダッシュボードを1つ受け取って、計算値・null値の扱い・スタック・系列数・タイトルと説明を直し、同じ欠陥を次のダッシュボードでも見つける検査ツールを作って、通過させます。
なぜ重要なのか
ダッシュボードが静かに間違う場所は、クエリではなくパネルオプションです。クエリは合っているのに、数字1つのパネルが平均を表示していると、20分間の急増は、6時間の平均の中で消えます。欠けた点をつないで描くと、収集が途切れたという事実そのものが消え、系列を積み重ねると、いちばん上の線を個々の値として読んでしまいます。3つとも「間違った値」ではなく、「尋ねていない問いの正確な答え」なので、見る人は、自分が間違って読んでいることに気づけません。そのため、パネルごとにどんな問いに答えるのかを説明として固定し、その約束を検査ツールで守らせます。
ステップ
lab-start-grafanaでGrafanaを起動し、欠陥が入ったダッシュボード/opt/lab/gfd/gfd-misread/broken.jsonを、修正せず、そのままGrafanaにアップロードしてください(uidはファイルに書かれたgfd-misread、パネルは6つ)。curlで/api/dashboards/dbにPOSTすればよいです。- パネル1(
요청률、韓国語のタイトルは「リクエストレート」という意味です)は、今、平均を表示しています。過ぎた区間を1つ選び(1時間以上、終わりは今より前)、その区間でsum(rate(http_requests_total{job="shop-api"}[5m]))の最後の値・平均・最大値を自分で測って、/root/gfd-misread/02-calc.txtに、start=、end=、last=、mean=、max=の5行で書いてください(startとendはエポック秒)。そして、パネル1の計算値をlastNotNullに変えて保存してください。 /root/gfd-misread/03-null.txtに、connected=、none=、zero=の3行を書いてください。各行は、そのnull値の扱いの選択が、見る人に何を主張するのかを、40文字以上で説明する必要があり、3行は互いに異なっている必要があります。そして、パネル2(대기열、韓国語のタイトルは「キュー」という意味です)のspanNullsをfalseに変えて保存してください。- パネル3(
핸들러별 요청률、韓国語のタイトルは「ハンドラー別のリクエストレート」という意味です)は、系列を積み重ねて描いています。過ぎた時刻を1つ選び、その瞬間の全体の合計と、/api/ordersの1つのハンドラーの値を、それぞれ測って、/root/gfd-misread/04-stack.txtに、at=、total=、orders=の3行で書いてください(atはエポック秒)。そして、パネル3のstacking.modeをnoneに変えて保存してください。 - パネル4(
핸들러 지연、韓国語のタイトルは「ハンドラーのレイテンシ」という意味です)のクエリは、ハンドラーごとに系列を1つずつ返します。その数を数えて、/root/gfd-misread/05-series.txtのbefore=に書き、このパネルが「いま最も遅いハンドラーのp95はいくつか」という1つの問いに答えるようにクエリを直して保存したあと、直したクエリの系列数をafter=に書いてください。 - 6つのパネルすべてについて、タイトルを、何を見るパネルなのかがわかるように直し(
그래프のような名前は禁止です。韓国語で「グラフ」を意味する語です)、説明には、そのパネルが答える問いの文を、疑問符で終わるように書いてください(12文字以上、パネルごとに異なる内容で)。直したダッシュボードを保存してください。 /root/gfd-misread/lint.pyを作成してください。ダッシュボードJSONファイルのパスを引数に受け取って、次の5つのルールの違反を1行に1つずつ(R1からR5までで始まる形で)出力し、違反が1つでもあれば、終了コード1で終わる必要があります。R1はstatパネルの計算値に平均が入っていること、R2はspanNullsが真であること、R3はstacking.modeがnormalであること、R4は説明が疑問符で終わっていないこと、R5はタイトルが空であるか、그래프・패널・차트(韓国語で順に「グラフ」「パネル」「チャート」を意味する語です)のいずれかであることです。原本の/opt/lab/gfd/gfd-misread/broken.jsonに対して実行して、5つのルールがすべて検出されるかを確認してください。- Grafanaにアップロードされている今のダッシュボードをそのままダウンロードして、
/root/gfd-misread/fixed.jsonに保存し(.dashboardの本体だけ)、検査ツールを実行して、違反が0で、終了コードが0であることを確認してください。そして/root/gfd-misread/08-review.mdに、R1=からR5=までの5行で、何をなぜ直したかを、それぞれ30文字以上で書いてください。
参考
- Grafanaは
lab-start-grafanaで起動します(数秒かかります)。Webプレビューの3000番ポートで、目でも確認してみてください。 - 欠陥が入った元のダッシュボードは
/opt/lab/gfd/gfd-misread/broken.jsonにあります。このファイルは修正せず、読むだけにしてください。ステップ8でもう一度使います。 - ダッシュボードを保存するAPIは
POST /api/dashboards/dbで、本文は{"dashboard": ..., "overwrite": true}です。 - 区間クエリは
/api/v1/query_range、ある瞬間の値は/api/v1/queryにtime=を一緒に送ります。どちらの経路も、/api/datasources/proxy/uid/<uid>/の後ろに付けて、Grafana経由で投げられます。 - よくある間違い①は、直したあとに保存しないことです。画面で変えても、APIで保存しなければ、採点ツールが見るのは古い版です。
- よくある間違い②は、区間を
지금(韓国語で「いま」を意味する語です)基準で取ることです。過ぎた絶対時刻で固定しておけば、もう一度測っても同じ値が出ます。 - パネルオプション · 標準オプション · ダッシュボードJSONモデル · ダッシュボードHTTP API · PrometheusクエリAPI
直す前の状態を画面に載せる
lab-start-grafanaでGrafanaを起動し、欠陥が入ったダッシュボード/opt/lab/gfd/gfd-misread/broken.jsonを、修正せず、そのままGrafanaにアップロードしてください(uidはファイルに書かれたgfd-misread、パネルは6つ)。curlで/api/dashboards/dbにPOSTすればよいです。
保存APIは、ダッシュボードの本体をdashboardキーの中に入れ、overwriteを一緒に送ります。ファイルからその形を作るには、jq -n --slurpfileが便利です。Grafanaが起動するのに数秒かかるので、/api/healthが応答するかどうかを、先に見てください。
数字1つのパネルは、何を計算した値なのか
パネル1(요청률、韓国語のタイトルは「リクエストレート」という意味です)は、今、平均を表示しています。過ぎた区間を1つ選び(1時間以上、終わりは今より前)、その区間でsum(rate(http_requests_total{job="shop-api"}[5m]))の最後の値・平均・最大値を自分で測って、/root/gfd-misread/02-calc.txtに、start=、end=、last=、mean=、max=の5行で書いてください(startとendはエポック秒)。そして、パネル1の計算値をlastNotNullに変えて保存してください。
区間クエリは/api/v1/query_rangeで、start・end・stepを一緒に送ります。データソースプロキシで投げれば、Grafanaが使うのと同じ経路で飛びます。計算値は、ダッシュボードJSONのoptions.reduceOptions.calcsにあります。固定した区間で測る理由は、あとでもう一度測っても同じ値が出るようにするためです。
欠けた点をつなぐことも、主張である
/root/gfd-misread/03-null.txtに、connected=、none=、zero=の3行を書いてください。各行は、そのnull値の扱いの選択が、見る人に何を主張するのかを、40文字以上で説明する必要があり、3行は互いに異なっている必要があります。そして、パネル2(대기열、韓国語のタイトルは「キュー」という意味です)のspanNullsをfalseに変えて保存してください。
収集が途切れた区間をつないで描くと、その時間にも値があったように見えます。null値の扱いは、fieldConfig.defaults.custom.spanNullsにあります。3つの選択が、それぞれどんな状況で正しいかも、一緒に考えてみてください。正しい答えが1つだけの問題ではありません。
積み上げたいちばん上の線は、どの系列でもない
パネル3(핸들러별 요청률、韓国語のタイトルは「ハンドラー別のリクエストレート」という意味です)は、系列を積み重ねて描いています。過ぎた時刻を1つ選び、その瞬間の全体の合計と、/api/ordersの1つのハンドラーの値を、それぞれ測って、/root/gfd-misread/04-stack.txtに、at=、total=、orders=の3行で書いてください(atはエポック秒)。そして、パネル3のstacking.modeをnoneに変えて保存してください。
ある瞬間の値は、/api/v1/queryにtime=を一緒に送れば得られます。時刻を固定しておくと、あとでもう一度測っても同じ値が出ます。スタックの設定は、fieldConfig.defaults.custom.stacking.modeにあります。2つの数字を比べてみると、いちばん上の線を個々の系列として読んだときに、どれだけ間違うかがわかります。
値1つを問うパネルに、系列が4つ来たら
パネル4(핸들러 지연、韓国語のタイトルは「ハンドラーのレイテンシ」という意味です)のクエリは、ハンドラーごとに系列を1つずつ返します。その数を数えて、/root/gfd-misread/05-series.txtのbefore=に書き、このパネルが「いま最も遅いハンドラーのp95はいくつか」という1つの問いに答えるようにクエリを直して保存したあと、直したクエリの系列数をafter=に書いてください。
promq "<쿼리>"で投げてみると(プレースホルダーはクエリです)、結果の系列が1行に1つずつ出ます。複数の系列のうち、最も大きい値1つだけを残す集計演算子があります。クエリは、ダッシュボードJSONのtargets[0].exprです。
タイトルと説明が、そのパネルの問いである
6つのパネルすべてについて、タイトルを、何を見るパネルなのかがわかるように直し(그래프のような名前は禁止です。韓国語で「グラフ」を意味する語です)、説明には、そのパネルが答える問いの文を、疑問符で終わるように書いてください(12文字以上、パネルごとに異なる内容で)。直したダッシュボードを保存してください。
説明は、ダッシュボードJSONのパネルごとにあるdescriptionです。画面では、パネルのタイトルの横にある情報アイコンとして表示されます。問いの文として書いておけば、半年後にこのパネルを削除してよいかどうかを判断できます。その問いをまだ尋ねているかどうかだけを見ればよいからです。
同じ欠陥を、次のダッシュボードでも見つける
/root/gfd-misread/lint.pyを作成してください。ダッシュボードJSONファイルのパスを引数に受け取って、次の5つのルールの違反を1行に1つずつ(R1からR5までで始まる形で)出力し、違反が1つでもあれば、終了コード1で終わる必要があります。R1はstatパネルの計算値に平均が入っていること、R2はspanNullsが真であること、R3はstacking.modeがnormalであること、R4は説明が疑問符で終わっていないこと、R5はタイトルが空であるか、그래프・패널・차트(韓国語で順に「グラフ」「パネル」「チャート」を意味する語です)のいずれかであることです。原本の/opt/lab/gfd/gfd-misread/broken.jsonに対して実行して、5つのルールがすべて検出されるかを確認してください。
ルールを文章で書いておくと、次のダッシュボードは、また同じ状態で生まれます。動くコードで書いてください。行(row)の中に畳まれたパネルもパネルであることを、忘れないでください。ファイルが{"dashboard": ...}で包まれている場合も、ダッシュボードの本体そのものである場合もあります。
直したダッシュボードが、自分自身の検査ツールを通る
Grafanaにアップロードされている今のダッシュボードをそのままダウンロードして、/root/gfd-misread/fixed.jsonに保存し(.dashboardの本体だけ)、検査ツールを実行して、違反が0で、終了コードが0であることを確認してください。そして/root/gfd-misread/08-review.mdに、R1=からR5=までの5行で、何をなぜ直したかを、それぞれ30文字以上で書いてください。
ファイルと画面が食い違わないようにするには、直したあとにもう一度ダウンロードする必要があります。検査ツールが0で終わらなければ、どのパネルが残っているかを出力が教えてくれます。記録は、次の人が同じ判断をもう一度しなくて済むように残すものです。