synthetic-monitoring-checks について
Grafana Synthetic Monitoring向けに、プローブからサービスの可用性やユーザージャーニーを検証するk6チェックの作成を支援するスキルです。信頼性監視と負荷テストを区別し、適切なチェック種別を選ぶ手順を示します。
主な機能
- 01HTTP、プロトコル、MultiHTTP、スクリプト、ブラウザチェックの選択
- 02Synthetic Monitoringの実行・タイムアウト制約への対応
- 03決定的なチェックとアサーションの作成
- 04デプロイ前のローカルスクリプト検証
- 05API仕様からユーザージャーニーチェックへの変換
活用シーン
- 01選択したプローブからAPIのユーザージャーニーを監視
- 02スクリプトを保守せずに静的エンドポイントを確認
- 03JavaScript描画のユーザージャーニーをブラウザチェックで検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ grafana/ skills --skill synthetic-monitoring-checksインストール後、Claude Code で/synthetic-monitoring-checksを入力して読み込まれたか確認します。
同梱ファイルreferences/api-and-terraform.md
詳細
合成モニタリングのチェック作成
ドキュメント: https://grafana.com/docs/grafana-cloud/testing/synthetic-monitoring/ Grafana Cloud Testing の幅広いエントリーポイント(SM + k6 Cloud + Faro):
testingスキル。
負荷テストではなく、信頼性のモニタリング
合成モニタリング(SM)は、k6 を信頼性/可用性エンジンとして実行します。各チェック実行では、固定スケジュールに従い、選択した各プローブロケーションから1 VU で 1 イテレーションを実行します。成功とは、「このリージョンから、今すぐユーザージャーニーが機能する」ことです。お客様より先に障害を検知できます。
負荷テストの慣習を適用しないでください。段階的に増やす VU、stages、負荷プロファイル、ソーク/ストレス/スパイクフェーズ、集約トラフィックに対するthresholdsはありません。用語は「チェック」「プローブ」「実行」「稼働時間」「到達可能性」「ユーザージャーニーの検証」を使用し、「負荷テスト」「ランプアップ」「VU」は使用しないでください。
ユーザーが実際に負荷テストまたはパフォーマンステスト(スループット、負荷時のレイテンシ、限界点)を求めている場合は、ここで止めてください。それは Synthetic Monitoring ではなく、Grafana Cloud k6 またはgrafana-k6プラグインのk6スキルの対象です。スクリプトは両製品で共有できますが、目的、オプション、料金は異なります。
実行モデルと制約(作成前に確認してください)
| 制約 | 値 |
|---|---|
| ワークロード | プローブ実行ごとに 1 イテレーション。スクリプト型と MultiHTTP は強制的に--vus 1 --iterations 1で実行されます。ブラウザチェックでは、スクリプトに必須の単一シナリオに依存します。いずれの場合も、vus、duration、stages、iterationsは無視されます。負荷形状は決して記述しないでください |
thresholds | サポートされていません |
| 頻度 | k6 クラスのチェック(スクリプト型、MultiHTTP、ブラウザ):60~3600 秒。プロトコルチェック(HTTP/ping/DNS/TCP/gRPC):1~3600 秒。Traceroute:120~3600 秒 |
| タイムアウト | 頻度以下である必要があります。k6 クラスのチェック:1~180 秒。プロトコルチェック:1~60 秒。Traceroute:固定で 30 秒 |
| k6 バージョン | チェックはk6 バージョンチャネルで実行されます(新しいチェックは既定で最新の安定チャネルを使用します。v1.xは 2026 年 7 月時点で非推奨です)。UI のドロップダウンまたは API/Terraform のchannelsでチェックごとに固定できます |
| ローカルファイル | open()、fs、grpc.load()はサポートされていません。ローカルモジュールはスクリプトにバンドルしてください。リモートのhttps://jslib.k6.io/...インポートは機能します |
| HTTP リクエストエラー | SM は k6 を--throw付きで実行します。ネットワークレベルのリクエスト失敗は例外をスローし、実行を失敗させます |
| SM が適用するスクリプトオプション | SM は独自の CLI フラグを設定し、スクリプトのoptionsオブジェクトより優先します。それでも有効なオプションは、batch、batch-per-host、discardResponseBodies、httpDebug、insecureSkipTLSVerify、maxRedirects、noConnectionReuse、setupTimeout、systemTags、tags、teardownTimeout、throw、tlsAuth、tlsCipherSuites、tlsVersion、userAgentです |
| ブラウザのメモリ | パブリックプローブ上の各ブラウザに 1GB RAM。巨大なページはTarget has crashedで失敗します |
| ブラウザスクリプトの形式 | UI はバンドル済み/ミニファイ済みブラウザスクリプトを拒否します(インポート検証)。これらは API または Terraform でデプロイしてください |
実行が失敗する仕組み(エージェントが誤りやすい点)
probe_success(1/0)は稼働時間のシグナルです。スクリプトが捕捉されない例外をスローする、fail() を呼び出す、k6-testing の expect() アサーションが失敗する(内部で k6 の test.abort() を呼び出します)、HTTP リクエストがネットワークレベルでエラーになる(SM の --throw)、またはタイムアウトに達した場合、実行は失敗としてマークされます。
単独で失敗した check() は、実行を失敗させません。probe_checks_total / probe_check_success_rate メトリクスを記録するだけです。しきい値がなければ、チェックは k6 の終了ステータスに影響しません。SM ではしきい値は無効になっています。
アサーションのパターン(推奨順):
import { expect } from 'https://jslib.k6.io/k6-testing/0.6.1/index.js';
import { check, fail } from 'k6';
// 1. PREFERRED — assertions module. Throws on failure => execution fails,
// with a descriptive error in the check logs.
expect(res.status, 'login should succeed').toEqual(200);
expect(res.json('token')).toBeDefined();
// 2. Soft assertions — run all of them, still fail the execution at the end.
expect.soft(res.headers['Content-Type']).toContain('application/json');
// 3. check() when you also want per-assertion metrics — but pair it with
// fail() or the failure won't affect probe_success/uptime:
check(res, { 'status 200': (r) => r.status === 200 }) ||
fail(`login failed with status ${res.status}`);
すべてのアサーションに名前を付けてください(メッセージ引数/チェック名)。失敗を午前3時に調査するとき、チェックログや probe_checks_total の check ラベルに表示されるのはこの名前です。
まず最もシンプルで十分なチェックタイプを選ぶ
お客様の費用負担が少なく、保守も簡単です。以下を順に確認し、最初に該当するものを選んでください。
- HTTP / ping / DNS / TCP / traceroute / gRPC — 単一の静的エンドポイント(稼働時間、ステータスコード、本文の正規表現、TLS 証明書の有効期限、レコード解決、ポート到達性)。保守するスクリプトは不要です。これらは blackbox-exporter のプローブエンジンで実行されます。タイプごとの
target形式を使った Terraform の例は、references/api-and-terraform.mdにあります。 - MultiHTTP — 値を受け渡し(
${variable}キャプチャ)ながら HTTP リクエストを順に実行しますが、カスタムロジックはありません。注意:MultiHTTP はステータスコードを自動検証しません。リクエストごとにアサーションを定義しないと、失敗が稼働時間に反映されません。 - k6 スクリプト — 暗号処理/署名、条件分岐、テストデータの生成、WebSocket、レスポンスに応じた連鎖処理など、実際のロジックが必要な API フロー。
- k6 ブラウザー — 実際のブラウザーが必要な場合に限ります。JS で描画されるユーザージャーニー、フォーム/クリック、Core Web Vitals などが該当します。
コストモデル(実行ベースの課金):1 回の実行は、1 つのプローブでチェックを 1 回実行することです。実行時間は分単位で計測され、端数は切り上げられます。月あたりの計算式:
probes × duration_minutes × (43200 / frequency_minutes)。API テストの実行(HTTP、ping、DNS、TCP、traceroute、MultiHTTP、スクリプト)とブラウザーテストの実行は別々に課金されます。ブラウザーチェックは高額な料金区分です。3 つのプローブで毎分実行するブラウザーチェックは、月あたり約 129,600 回のブラウザー実行になります。同じチェックを 5 分ごとに実行すると、約 25,920 回です。検知時間の目標を満たす範囲で最も長い実行間隔を選び、ユーザーの近くに 2~3 個のプローブを配置してください(複数のプローブでアラートの頻繁な変動を抑えられます。数を増やせばよいというものではありません)。
スクリプトチェックの作成
生成するすべてのスクリプト(スクリプトチェックとブラウザーチェックの両方)は、以下のスケルトンのように、1 行目を出典コメントにしてください。このコメントにより、後でチェックを読む人は作成方法(およびスキルの場所)を確認できます。また、固定の接頭辞を使うことで、スキルによって作成されたチェックを検索できます。Generated by synthetic-monitoring-checks はそのまま使用し、タイムスタンプだけを変えてください(date -u +%Y-%m-%dT%H:%M:%SZ)。
スケルトン — シークレットと失敗時に実行を止めるアサーションを使ったログイン+API アクションのジャーニー:
// Generated by synthetic-monitoring-checks (https://github.com/grafana/skills) on 2026-07-31T12:00:00Z
import http from 'k6/http';
import { expect } from 'https://jslib.k6.io/k6-testing/0.6.1/index.js';
import secrets from 'k6/secrets';
const BASE = 'https://api.example.com';
export default async function () {
// Secrets are managed in Synthetics > Config > Secrets — never hardcode credentials.
const password = await secrets.get('checkout-monitor-password');
// Step 1: authenticate with a dedicated monitoring account
const login = http.post(
`${BASE}/auth/login`,
JSON.stringify({ user: 'sm-checkout-monitor', password }),
{ headers: { 'Content-Type': 'application/json' } }
);
expect(login.status, 'login should return 200').toEqual(200);
const token = login.json('token');
expect(token, 'auth token should be present').toBeDefined();
// Step 2: exercise the journey and assert the OUTCOME, not just the status
const order = http.post(`${BASE}/orders`, JSON.stringify({ sku: 'TEST-SKU-1', qty: 1 }), {
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
});
expect(order.status, 'order should be created').toEqual(201);
const orderId = order.json('id');
expect(orderId, 'order id should be returned').toBeDefined();
// Step 3: clean up so the check is idempotent against production
// http.url groups metrics for URLs containing unique IDs — without it, every
// execution creates new time series (cardinality + active-series cost).
const del = http.del(http.url`${BASE}/orders/${orderId}`, null, {
headers: { Authorization: `Bearer ${token}` },
});
expect(del.status, 'test order should be cleaned up').toEqual(204);
}
スクリプトチェックを優れたテストではなく、優れたモニターにするためのルール:
- 決定論的にする:固定のテストデータ(または上記のように、生成して削除するデータ)を使い、時刻や順序に依存させないでください。どのプローブからでも、何時に実行しても、毎回成功する必要があります。
- 本番環境に対して冪等にする:作成後に削除するか、読み取り専用のエンドポイントを使ってください。チェックは永続的に実行されるため、残った状態も永続的に蓄積します。
- 専用のテストアカウントを使う:実ユーザーの認証情報は絶対に使わないでください。権限を最小限にし、パスワードは SM のシークレットとして保存し、そのアカウントを分析/課金から除外してください。
- すべてのステップをアサートする — アサーションのないステップが失敗すると、後続のステップで分かりにくい失敗が発生します。
- URL のカーディナリティを安定させる:ID を含む URL には
http.urlのテンプレートリテラルを使ってください。 - 実行時間はタイムアウトを十分に下回るようにし、タイムアウトは実行間隔より短くしてください。
OpenAPI 仕様(または類似の仕様)からチェックを生成する
API の説明(OpenAPI/Swagger 仕様、GraphQL スキーマ、または Postman コレクション)があれば、k6 呼び出しへの機械的な変換は簡単です。重要なのは、何を変換するかです。
- エンドポイントではなく、ユーザージャーニーを選びます。 パスごとにチェックを1つ生成したり、すべてのパスを網羅するチェックを1つ生成したりしてはいけません。それではサービスではなく仕様を監視することになり、チェックを追加するたびに実行コストが増大します。「顧客に影響が出る」障害につながる1〜3個のフロー(認証 → 中核となる操作 → 結果)を特定し、フローごとにスクリプト化されたチェックを1つ作成します。
- 安全性を基準に絞り込みます。 変更を伴う操作(
POST/PUT/DELETE)を含めるのは、フロー内で後処理を行う場合(上記のように作成後に削除するなど)、または専用のテストリソースを対象にする場合に限ります。仕様には破壊的な操作がヘルスエンドポイントのすぐ隣に記載されていることがあります。文書化されているからといって、本番環境で実行してはいけません。 - レスポンススキーマに基づいてアサーションを行います。 仕様には正常なレスポンスに含まれる内容が明記されています。ステータスコードだけでなく、必須フィールドも検証します。
expect(order.json('id'), 'id required by OrdersResponse schema').toBeDefined() - ターゲット URL を確認します。
servers:ブロック(および Postman 環境)には、localhost やステージング環境が先に記載されていることがよくあります。ユーザーに本番環境のベース URL を確認し、securitySchemesの認証情報を SM のシークレットに割り当てます。仕様に直接記載された値は使用しないでください。 (プレーンな HTTP/プロトコルチェックでのシークレット使用は、最近導入された機能フラグ付きのロールアウトです。最新のドキュメントを確認してください。スクリプトでsecrets.get()を使う方法は常に利用できます。) format: int64の ID は文字列として扱います。res.json('id')は値を JS の数値として解析するため、2^53 を超える値(snowflake 形式の ID など)は気付かないうちに破損します。その結果、作成処理は正常に見える一方、読み取り確認用の URL は実行のたびに 404 になります。代わりに、未加工の本文から抽出します。const id = (/"id":\s*(\d+)/.exec(res.body) || [])[1];また、ID に対して算術演算を行ってはいけません。
API 仕様がまったくありませんか? フロントエンドを調べます。ブラウザーの開発者ツールでウェブアプリを開くか(または curl で想定されるルートにアクセスし)、アプリが呼び出す /api/* の XHR リクエストを記録します。文書化されたバックエンドサービスが gRPC 専用または内部向けであっても、これは監視可能な HTTP インターフェースです。
ブラウザチェックの作成
必須のひな形:k6/browser をインポートし、chromium ブラウザーの型を宣言します。UI では両方が検証されます。
// Generated by synthetic-monitoring-checks (https://github.com/grafana/skills) on 2026-07-31T12:00:00Z
import { browser } from 'k6/browser';
import { expect } from 'https://jslib.k6.io/k6-testing/0.6.1/index.js';
import secrets from 'k6/secrets';
export const options = {
scenarios: {
ui: {
executor: 'shared-iterations',
options: { browser: { type: 'chromium' } },
},
},
};
export default async function () {
const page = await browser.newPage();
try {
await page.goto('https://shop.example.com/login');
// Prefer role/label/test-id locators over CSS chains — they survive redesigns.
const password = await secrets.get('shop-monitor-password');
await page.getByLabel('Email').fill('[email protected]');
await page.getByLabel('Password').fill(password);
await page.getByRole('button', { name: 'Sign in' }).click();
// Assert the JOURNEY OUTCOME with auto-retrying assertions — never sleep().
await expect(page.getByRole('heading', { name: 'Your account' })).toBeVisible();
await page.getByRole('link', { name: 'Orders' }).click();
await expect(page.getByTestId('order-list')).toBeVisible();
} finally {
await page.close();
}
}
ブラウザー固有のルール:
- ロケーター:
getByRole/getByLabel/getByTestId(必要に応じてアプリチームにdata-testidの追加を依頼します)> テキスト > CSS の順に使用します。XPath や生成されたクラス名は使用しないでください。getByTestIdはdata-testidを前提としています。Cypress 用に計測されたアプリではdata-cyが使われることが多いため、代わりにpage.locator('[data-cy="..."]')を使用してください。 - 操作の前に手動で待機しない:ロケーターの操作は、表示状態と有効状態になるまで自動で待機します。
click()/fill()の前にwaitFor()を呼び出したり、waitForLoadState()を使用したり、sleep()を呼び出したりしないでください。 - 自動リトライする
expect()(toBeVisible、toBeEnabledなど)は、操作しない状態を検証するための待機手段です。 注意点:リトライすると記載されているものの、テキストマッチャー(toHaveText/toContainText)は、 最初の 不一致 の読み取りで失敗します。たとえば、クライアント側でレンダリングされるアプリのハイドレーション中に 空文字列が読み取られる場合があります。動的なテキストは、そのテキストを特定して表示状態を検証してください:await expect(page.getByText('Order confirmed')).toBeVisible() - アサーションのタイムアウトは既定で 5s — クライアント側でレンダリングされるアプリでは、意味のある表示が始まるまでに
これを超える時間がかかることがよくあります。一度だけ引き上げ、設定済みのインスタンスを使用してください:
const expectUi = expect.configure({ timeout: 20000 }); - 結果を検証する(ログイン後の見出し、注文リスト、確認テキストなど)— ページが正常に読み込まれても、 一連の操作が失敗していることがあります。
try/finallyとpage.close()を使用することで、アサーションが例外をスローした場合もブラウザーを解放します。- スクリーンショットの成果物は、文書化された SM 機能ではありません。
page.screenshot()を使った失敗処理を構築せず、 アサーションのメッセージとチェックのログ(SM は実行ごとのログを Loki に保存します)を活用してください。 - Web Vitals(
probe_browser_web_vital_lcp|cls|fcp|inp|ttfb)は自動的に収集されるため、追加のコードは不要です。
ローカルで検証してからデプロイする
SM スクリプトは通常の k6 スクリプトです。必ず最初にローカルで実行してください:
k6 run script.js # scripted check
K6_BROWSER_HEADLESS=true k6 run browser-check.js # browser check
k6 run --secret-source=mock=checkout-monitor-password=example-password script.js # with secrets
# Many/large secrets: k6 run --secret-source=file=secrets.txt script.js
成功の条件は、終了コードが 0、イテレーションが 1 回、サマリーに失敗したアサーションがないことです。3~5 回実行してください。 ローカルでの成功率が 90% のスクリプトでも、プローブが 3 つあれば毎晩ページャーが鳴ることになります。
次のいずれかを選んでチェックを作成します:
- UI:Testing & synthetics → Synthetics → Add new check → k6 scripted / k6 browser → スクリプトを貼り付け → プローブと頻度を選択 → Test(保存せずに 1 回実行)→ Save。
- gcx:
gcx synthetic-monitoring checks test -f check.yamlは、UI の Test ボタンに相当する CLI コマンドです。保存せずに、実際のプローブに対して 1 回実行します。 次にgcx synthetic-monitoring checks create -f check.yamlを実行して保存します。どちらのコマンドもスクリプトを プレーンテキストで受け取り、gcx が base64 エンコードします。既存のチェックを取得して開始用のテンプレートにするには、gcx synthetic-monitoring checks get <ID> -o yaml --decode-scriptを実行します(フラグを省略すると、未加工の base64 が返されます)。 - API または Terraform:
references/api-and-terraform.mdを参照してください。 主な注意点:API のfrequency/timeoutは ミリ秒単位で、settings.scripted.script/settings.browser.scriptは base64 エンコードされています。Terraform ではfile()を使ってプレーンテキストのスクリプトを渡します。
好みではなく、管理体制に応じて選択してください。チェックがすでに Terraform で管理されている場合(ドリフト検出、複数環境、
PR レビューなど)は、Terraform を通じて作成・更新してください。Terraform が管理する状態を手動編集すると、次の
apply でドリフトが発生します。それ以外の場合、単発の作成やエージェント主導の作成では、gcx または UI の方が高速です。
どのツールでチェックをプロビジョニングしたかにかかわらず、ライブ検査、アドホックなテスト、ステータスやタイムラインの調査には
引き続き gcx を使用できます。
動作確認とロールバック
1 frequency interval 待ってから、Synthetic Monitoring メトリクスの (Prometheus)データソースを使って Explore で確認します。
# 1 from every selected probe = healthy
probe_success{job="checkout-flow"}
# Assertion pass rate per named assertion (scripted/browser)
probe_check_success_rate{job="checkout-flow"}
# Journey duration per probe — confirm it's comfortably under the timeout
probe_script_duration_seconds{job="checkout-flow"}
# Uptime over time (how the SM app computes it)
max by () (max_over_time(probe_success{job="checkout-flow"}[5m]))
最初の実行が正常な場合は、すべてのプローブで probe_success == 1 となり、すべての
probe_check_success_rate シリーズが 1 で、プローブ間で所要時間が安定し、チェックの
組み込みダッシュボード(Synthetics → check → View dashboard)に各実行のログが表示されます。
ブラウザーチェックでは、さらに probe_browser_web_vital_* シリーズが表示されます。
ロールバック:チェックの enabled: false(UI の切り替え、gcx synthetic-monitoring checks update、API の更新、または Terraform)を設定すると、履歴を失わずに実行を
停止できます。設定が不要になった場合にのみ、チェックを削除してください。アラート:
まず alertSensitivity または probe_success に対するデフォルトのアラートルールを使います。
アラートルールの例は、testing スキルを参照してください。
よくある失敗パターン
| 症状 | 原因 → 対処 |
|---|---|
| ローカルでは成功するが、すべてのプローブで失敗する | ターゲットにパブリックインターネットからアクセスできません(内部 DNS、VPN、IP 許可リスト)。内部ターゲットにはプライベートプローブを使用するか、プローブの送信元を許可リストに追加してください |
| ローカルでは成功するが、一部のプローブで失敗する | 地域制限、地域ごとの CDN/WAF ルール、またはデータセンターの IP にチャレンジするボット対策。失敗時の probe ラベルを確認し、WAF で SM の userAgent または該当する地域を除外してください |
目視ではチェックが「失敗」しているのに、probe_success は 1 のまま | fail()/expect() を使わない単独の check() — 失敗はメトリクスとしてのみ記録されます。expect() または check(...) || fail(...) に変更してください |
| ブラウザーチェックでロケーターのタイムアウトが頻発する | 脆弱なセレクター、またはアニメーションのタイミングが原因です。getByRole/getByTestId に切り替え、自動再試行する expect() でアサートし、手動の待機を削除してください |
toBeVisible が Expected: visible / Received: hidden と報告するが、要素は明らかに表示されている | ロケーターが複数の要素に一致しています(厳密モード)— エラーメッセージは誤解を招きます。セレクターを絞り込むか、.first() を使ってください |
| 作成は成功するが、すべての実行で読み戻しが 404 になる | ID が Number.MAX_SAFE_INTEGER(2^53)を超えており、res.json() が気付かないうちに丸めています — 生の本文から int64 ID を文字列として抽出してください(OpenAPI のセクションを参照) |
secrets.get() が失敗する | シークレット名の不一致(名前は完全一致で、253 文字以下、使用できる文字は英字/数字/-/_)、シークレットの削除(再作成するまでチェックは失敗します)、または編集ユーザーに Admin/Editor ロールか「Checks writer」権限がありません |
| ジャーニーには問題がないのに、実行がタイムアウトする | ジャーニーに対してタイムアウトが短すぎます(最大 180s)— タイムアウトを延長してください。または、スクリプトが反復ごとに上限のない処理を行っています。タイムアウトが頻度より短いことも確認してください |
ブラウザーチェックのログに Target has crashed と表示される | ページがプローブブラウザーのメモリ上限 1GB を超えています — ジャーニーを短縮し、容量の大きいサードパーティーリソースをブロックするか、メモリの多いプライベートプローブを使用してください |
| UI がブラウザースクリプトを拒否する | バンドル/圧縮されたスクリプトが UI のインポート検証に失敗しています — 代わりに API または Terraform で作成してください |
| チェックの追加後、メトリクス/請求額が急増する | URL 内の一意な ID によって実行ごとの時系列が生成されています — http.url を使用し、チェック頻度 × プローブ数を上記のコスト計算式と照らし合わせてください |
参考資料
references/api-and-terraform.md— SM API 認証とチェックの CRUD ペイロード(スクリプト、ブラウザー、MultiHTTP)、およびプロトコルチェック(HTTP、ping、DNS、TCP、traceroute、gRPC)を含む、すべてのチェックタイプの Terraform 例
リソース
- Synthetic Monitoring のドキュメント
- k6 スクリプトチェック · k6 ブラウザチェック
- シークレット管理
- k6 アサーション(
expect) · k6 ブラウザモジュール - k6 の基礎と負荷テスト:
grafana-k6プラグイン、k6スキル