mcpField
G
groundcover-cli

groundcover-cli

github.com/paymogクラウド・DevOps19.4k 回インストール10 週間前に更新
リポジトリ

groundcover-cli について

Groundcover の可観測性プラットフォームを操作するコマンドラインスキルです。テレメトリー、ダッシュボード、モニター、設定を管理するユーザー向けで、型付き SDK コマンドと SDK 未対応のエンドポイントへのアクセスを備えています。

主な機能

  1. 01型付きリソースの CRUD 操作
  2. 02ログ、トレース、メトリクスの検索
  3. 03追加エンドポイントへの raw アクセス
  4. 04認証プロファイルと認証情報の管理
  5. 05Grafana ダッシュボードと設定の管理

活用シーン

  1. 01テレメトリーの検索とサービス状態の確認
  2. 02モニターやダッシュボードの作成・更新
  3. 03SDK 未対応エンドポイントの詳細情報へのアクセス

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/paymog/groundcover-cli --skill groundcover-cli

インストール後、Claude Code で/groundcover-cliを入力して読み込まれたか確認します。

詳細

Groundcover CLI

groundcover バイナリを呼び出します(brew install paymog/tap/groundcover でインストール)。情報源は paymog/groundcover-cli です。

認証(すべてのコマンドの実行前に必須)

export GROUNDCOVER_API_KEY=gcsa_...   # must be a service-account key

キーはサービスアカウントキーである必要があります。プレフィックスは gcsa_、長さは正確に 40 文字です。 それ以外は明確なメッセージとともに拒否されます — Invalid token prefix. Expected 'gcsa_' または Invalid token length (N, expected 40)。キーの種類を混同しないでください。

  • gcsa_… — サービスアカウントキーです。クエリ/CRUD コマンドで必要なのはこちらです。
  • gcik_… — インジェストキーです(データのプッシュ用)。API の認証には使用できません。種類が異なります。

正しい形式の gcsa_ キーで 401 が返される場合、そのキーはクエリ対象とは別のテナントに属しています。

手元に gcsa_ キーがない場合は、有効なキーを使って groundcover service-accounts create で作成し、セッションで export GROUNDCOVER_API_KEY=gcsa_… を実行してください。

組み込みのデフォルト値:

  • --base-url https://api.groundcover.com
  • --backend-id groundcover

テナント UUID のデフォルト値はありません。Grafana 以外の raw … パススルー呼び出しで X-Tenant-UUID ヘッダーを送信するには(テナント間アクセスなど)、--tenant-uuid / GROUNDCOVER_TENANT_UUID を設定してください。組み込みの Grafana raw grafana … エンドポイントでは無視されます(下記の Grafana セクションを参照)。

raw grafana … コマンドでは gcsa_ キーは一切使用しません。Grafana サービスアカウントトークン(glsa_…)が必要です。GROUNDCOVER_GRAFANA_SERVICE_ACCOUNT_TOKEN / --grafana-token を設定してください。

環境変数での上書き:GROUNDCOVER_BACKEND_ID、GROUNDCOVER_TENANT_UUID、GROUNDCOVER_GRAFANA_SERVICE_ACCOUNT_TOKEN、GROUNDCOVER_BASE_URL(または対応する GC_*)。同じ名前の値は、--api-key、--backend-id、--tenant-uuid、--grafana-token、--base-url フラグでも設定できます。

保存済みプロファイル(環境変数の代替)

毎回のセッションで GROUNDCOVER_API_KEY をエクスポートする代わりに、認証情報を名前付きプロファイルに保存できます。API キーは OS のキーリングに保存され、メタデータ(バックエンド ID、ベース URL、テナント UUID)は ~/.config/groundcover/profiles.yaml に保存されます。

groundcover auth login [name] --backend-id <id>   # prompts for key (or --key); validates before saving
groundcover auth list                              # * marks default
groundcover auth default <name>                    # change default
groundcover --profile <name> <command>             # use a profile for one command
groundcover auth status                            # show resolved source
groundcover auth token                             # print resolved key
groundcover auth logout <name> [-f]

優先順位:--api-key/GROUNDCOVER_API_KEY 環境変数 → --profile <name> → デフォルトプロファイル。明示的なキーと --profile を同時に指定すると、曖昧な指定として拒否されます。GROUNDCOVER_PROFILE を設定すると、環境変数でプロファイルを指定できます。

その他のグローバルフラグ:--timeout(デフォルトは 30s)、--raw(JSON レスポンスを再フォーマットしません)。

2 つのインターフェース

インターフェース用途
SDK ベース(groundcover <resource> <verb>)最初に使います。安定したコントラクトと型付きリクエストボディを提供します。
Raw HAR 由来(groundcover raw …)SDK にないエンドポイントを使う場合、または SDK にないランナー機能が必要な場合に使います(下記参照)。

常にまず SDK 形式を試してください。

raw で SDK にない機能
  • --set dotted.path=value — ボディに対するドット区切りパスの上書きをディープマージします
  • --query key=value(繰り返し指定可能)— 任意のクエリ文字列パラメーターを上書きします
  • Web アプリの HAR から取得した組み込みのデフォルトボディ(SDK では --body-file/--body-json の明示的な指定が必要です)
  • --tenant-uuid / GROUNDCOVER_TENANT_UUID を設定すると、Grafana 以外の raw 呼び出しで X-Tenant-UUID を送信します(テナント間アクセス用。SDK のトランスポートでは、それ以外の場合、API キーからテナントを判定します)。Grafana の raw grafana … コマンドでは使用されません。代わりに glsa_ トークンで認証します。
  • groundcover raw list ですべての取得済みエンドポイントを確認できます

どちらのインターフェースも --body-file(json/yaml)、--body-json、--raw 出力をサポートしています。

raw のみのエンドポイント(SDK コマンドはまだありません)

これらの操作には groundcover raw … を使用してください。SDK には親リソースはありますが、詳細表示はありません。

  • ログ: filters、velocity(SDK には search のみ)
  • トレース: attributes、details、errors、filters、insights、latencies、requests、values-distribution(SDK には search のみ)
  • メトリクス: cardinality、cardinality-graph、discovery、labels-cardinality、query-range、resources errors|latencies|list|requests(SDK には query、names、keys、values があります)
  • prometheus: prometheus api query(Prom の raw パススルー。--query query='up' を使ったアドホックな PromQL クエリに便利です)
  • Grafana ダッシュボード: grafana search、grafana dashboards get|save|delete、grafana dashboards permissions get|update、grafana dashboards versions|get|restore、grafana folders list|get|create|update|delete、grafana folders permissions get|update、grafana annotations list|create|update|delete、grafana prometheus rules、grafana datasources label-values、grafana ds query
  • モニターの詳細表示: instances filters|query|timeline、labels keys、silences、summary filters|query、timeline(SDK には CRUD のみ)
  • k8s の詳細表示: configmaps|cronjob|daemonsets|deployments|jobs|pods|pvcs|replicasets|statefulsets list、container info、context events、namespaces info|list、nodes info-with-resources|list|resources|usage top10、pod container usage、pods status-over-time、workloads availability|events|usage top10、network connections|cross-az|cross-az-regions|partners|throughput|top-connections、events search-time-series(SDK には clusters、workloads、events-search、events-over-time があります)
  • インフラ: infra hosts info-with-resources
  • リソース/RUM: resources apis errors|filters|latencies|list|requests、rum sessions filters|query、sources list
  • パイプラインの統計: pipelines logs current-stats、pipelines traces current-stats(SDK で実行できるのは設定の CRUD のみ)
  • テナント/課金/RBAC の読み取り: rbac seatsUsage、rbac tenant ai-settings、rbac tenant settings、backend settings、billing method、agent token-budgets|token-usage|token-usage history|token-usage tenant
  • ストレージ管理: 保持期間、gcQL 例外ルール、インデックス階層の設定には、storage-management get|update --data-type <logs|traces|events|measurements|monitor_instance> を使用します
  • その他: graph、graph filters、views member、views member defaults、migrations、connectors list org|personal、synthetics rules、aggregations metrics config|config default、integrations data config

実行前に groundcover raw list/groundcover raw list <group> を実行して、正確な名前を確認してください。

SDK 対応の CRUD パターン

groundcover <resource> list   [--query '<filter>']
groundcover <resource> get    <id>
groundcover <resource> create --body-file <file>   # or --body-json '<json>'
groundcover <resource> update <id> --body-file <file>
groundcover <resource> delete <id>

本文ファイル:.json または .yaml。

リソース(すべて上記のパターンに従います)
  • ダッシュボード — archive <id>、restore <id> も使用できます
  • モニター — --query 'monitor_name = "cpu"'
  • サイレンス — list --active
  • 定期サイレンス
  • 接続済みアプリ — --query 'type:slack-webhook'
  • 通知ルート — --query 'prod'
  • 合成モニタリング
  • シークレット — hash <id> も使用できます
  • ワークフロー
認証/RBAC
groundcover api-keys list
groundcover api-keys create --body-file key.json
groundcover service-accounts list
groundcover service-accounts create --body-file sa.json
groundcover ingestion-keys list
groundcover policies list
groundcover policies apply --body-file policy.json
groundcover policies audit-trail <id>
パイプラインのシングルトン(get/create/update/delete、id なし)
groundcover logs-pipeline get
groundcover metrics-pipeline get
groundcover traces-pipeline get
groundcover metrics-aggregator get
インテグレーション(型指定)
groundcover integrations list
groundcover integrations describe <type>
groundcover integrations create <type>      --body-file config.json
groundcover integrations update <type> <id> --body-file config.json
可観測性/読み取りコマンド(本文ファイルを使用)
groundcover logs search          --body-file body.json
groundcover traces search        --body-file body.json
groundcover metrics query        --body-file body.json   # PromQL range/instant
groundcover metrics names        --body-file body.json   # list metric names
groundcover metrics keys         --body-file body.json   # label keys for a metric
groundcover metrics values       --body-file body.json   # label values for a key
groundcover search discovery     --body-file body.json   # facet / discovery
groundcover search keys          --body-file body.json
groundcover search values        --body-file body.json
groundcover k8s clusters         --body-file body.json
groundcover k8s workloads        --body-file body.json
groundcover k8s events-search    --body-file body.json
groundcover k8s events-over-time --body-file body.json

フィールドを抽出するには jq にパイプするか、--raw を指定してレスポンスをそのまま出力します。

可観測性の本文テンプレート

時刻には RFC 3339 UTC(2026-05-28T00:00:00Z)を使用します。現在時刻を壁時計から取得する機能は組み込まれていないため、date -u で計算してください。すべての検索は同じ形式です(logs search、traces search、k8s events-search)。

{
  "start": "2026-05-28T00:00:00Z",
  "end":   "2026-05-28T01:00:00Z",
  "query": "<GCQL>",
  "filters": "",
  "sources": []
}

metrics query(フィールド名は大文字で始まる点に注意してください。これは API の仕様です):

{
  "Promql":    "rate(http_requests_total[5m])",
  "Start":     "2026-05-28T00:00:00Z",
  "End":       "2026-05-28T01:00:00Z",
  "Step":      "60",
  "QueryType": "range",
  "Conditions": []
}

ポイントクエリには "QueryType": "instant" を使用し、Step は省略してください。

k8s workloads/k8s clusters:

{
  "conditions":  [],
  "sources":     [],
  "gcqlFilter":  "namespace = 'prod'",
  "limit":       100
}

Raw コマンド

groundcover raw list                          # list groups
groundcover raw list <group>                  # list commands in group
groundcover raw k8s clusters list
groundcover raw dashboards get --dashboard-id <id>
groundcover raw metrics query-range --body-file body.json
groundcover raw prometheus api query --query query='up'
groundcover raw grafana dashboards get --dashboard-uid <uid>
groundcover raw grafana dashboards save --body-file dashboard.json
groundcover raw grafana folders list
groundcover raw grafana ds query --body-file query.json
ストレージ管理

管理者は、logs、traces、events、measurements(APM)、monitor_instance(モニターの問題)のライフサイクル設定を読み取り、更新できます。

groundcover raw storage-management get --data-type logs --raw \
  | jq '{retention,version,cold_move_duration,cold_volume,custom_rules:(.custom_rules // [])}' \
  > storage.json
# Edit storage.json, preserving every writable field and the complete rule list.
groundcover raw storage-management update --data-type logs --body-file storage.json

更新では楽観的同時実行制御を使用し、書き込み可能な設定ドキュメントを置き換えます。必ず get から始め、現在の version を引き継ぎ、retention、cold_move_duration、cold_volume、および custom_rules の全リストを保持してください。custom_rules を省略すると、既存のルールが削除されます。更新が成功すると、version が増加します。確認された各カスタムルールには、name、retention、および gcQL の filters 式が含まれます。

Grafana ネイティブダッシュボード

Groundcover には /grafana の Grafana も組み込まれています。これらは Groundcover のファーストクラスの dashboards SDK リソースとは異なるため、ネイティブの Grafana JSON ダッシュボード、フォルダー、権限、アノテーション、データソースに基づく変数値、またはパネルクエリの実行が必要な場合は、raw grafana … を使用してください。

認証: 組み込みの Grafana はセッション認証が必要なプロキシの背後にあり、gcsa_ API キー、バックエンド ID、テナント UUID は無視されます。/grafana/api/* へのベアラー/gcsa_ リクエストは、常に約 980 KB の Grafana SPA index.html(HTTP 200、text/html)を返し、JSON は返しません。これらのコマンドには、代わりに Grafana サービスアカウントトークン(glsa_…)が必要です。GROUNDCOVER_GRAFANA_SERVICE_ACCOUNT_TOKEN(または --grafana-token)を設定してください。トークンを設定せずに raw grafana … コマンドを実行すると、CLI に完全なセットアップガイドが表示されます。

トークンの生成(groundcover テナント管理者が必要です)。トークンは groundcover の公式 CLI(github.com/groundcover-com/cli)から取得しますが、こちらも残念ながら groundcover という名前のバイナリをインストールします。インストーラーはこれを ~/.groundcover/bin/groundcover に配置し、そのディレクトリを PATH の先頭に追加するため、その後 groundcover は公式 CLI を指すようになり、この CLI より優先されます。競合を避けるため、公式バイナリをフルパスで呼び出してください。

sh -c "$(curl -fsSL https://groundcover.com/install.sh)"      # installs to ~/.groundcover/bin
~/.groundcover/bin/groundcover auth login                     # auth flow
~/.groundcover/bin/groundcover auth generate-service-account-token   # prints glsa_… once
export GROUNDCOVER_GRAFANA_SERVICE_ACCOUNT_TOKEN=glsa_...     # hand it to this CLI

この CLI を groundcover として使い続けるには、インストーラーがシェルの rc に追加した ~/.groundcover/bin の PATH 行を削除してください。

一般的なコマンド:

groundcover raw grafana search --query query='service slo' --query folderUIDs=general
groundcover raw grafana dashboards get --dashboard-uid streamling-pipeline-slo
groundcover raw grafana dashboards save --body-file dashboard.json
groundcover raw grafana folders list
groundcover raw grafana datasources label-values --datasource-uid <uid> --label project_id --query start=<unix> --query end=<unix>
groundcover raw grafana ds query --query ds_type=prometheus --body-file query.json

Grafana の raw コマンドはデフォルトで https://app.groundcover.com(Web アプリのホスト)を使用します。一方、通常の API/SDK コマンドはデフォルトで https://api.groundcover.com を使用します。標準以外のデプロイメントでのみ --base-url を指定してください。

Raw フラグ:--body-json、--body-file、--set dotted.path=value、--query key=value(繰り返し指定可能)、生成されたパスフラグ(例:--dashboard-id)、--raw。多くの raw コマンドには Web アプリの HAR から取得したデフォルトの本文が用意されているため、--body-* を指定せずに実行し、--set で特定のフィールドを上書きできます。

レシピ

サービスの直近 1 時間のエラーログ
END=$(date -u +%FT%TZ); START=$(date -u -v-1H +%FT%TZ)   # GNU: date -u -d '1 hour ago' +%FT%TZ
jq -n --arg s "$START" --arg e "$END" '{
  start:$s, end:$e,
  query: "service_name = \"api\" AND level = \"error\"",
  filters: "", sources: []
}' | groundcover logs search --body-file /dev/stdin | jq '.[] | {ts:.timestamp, pod:.pod_name, body:(.body|fromjson?)}'

logs search はルートに JSON 配列をそのまま返します — .logs[] ではなく、jq '.[]' を使用してください。人が読めるメッセージは body フィールドに JSON 文字列として格納されています(fromjson で解析します)。便利なトップレベルフィールド:pod_name、container_name、namespace、workload、level(小文字に正規化済み — body 内に表示される WARN/DEBG ではなく、error/warning/debug)、cluster、timestamp、trace_id。

ワークロードの p99 レイテンシ(直近 30 分、PromQL)
END=$(date -u +%FT%TZ); START=$(date -u -v-30M +%FT%TZ)
jq -n --arg s "$START" --arg e "$END" '{
  Promql: "histogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket{service=\"api\"}[5m])))",
  Start: $s, End: $e, Step: "60", QueryType: "range", Conditions: []
}' | groundcover metrics query --body-file /dev/stdin
クラッシュループまたは再起動を繰り返すポッド
jq -n '{ conditions: [], sources: [], gcqlFilter: "status != \"Running\"", limit: 200 }' \
  | groundcover k8s workloads --body-file /dev/stdin \
  | jq '.workloads[] | select(.restarts > 0) | {name, namespace, status, restarts}'
名前空間の最近の k8s イベント
END=$(date -u +%FT%TZ); START=$(date -u -v-1H +%FT%TZ)
jq -n --arg s "$START" --arg e "$END" '{
  start:$s, end:$e,
  query: "namespace = \"prod\" AND type = \"Warning\"",
  filters: "", sources: []
}' | groundcover k8s events-search --body-file /dev/stdin
遅いトレースを見つけてから、ログに切り替える
END=$(date -u +%FT%TZ); START=$(date -u -v-30M +%FT%TZ)
jq -n --arg s "$START" --arg e "$END" '{
  start:$s, end:$e,
  query: "service_name = \"api\" AND duration_ms > 1000",
  filters: "", sources: []
}' | groundcover traces search --body-file /dev/stdin \
  | jq -r '.[] | .trace_id' | head -5 \
  | while read tid; do
      jq -n --arg s "$START" --arg e "$END" --arg t "$tid" '{
        start:$s, end:$e, query: ("trace_id = \"" + $t + "\""), filters: "", sources: []
      }' | groundcover logs search --body-file /dev/stdin
    done
ストリームに存在するラベル/フィールドを確認する
# What metric names match a prefix?
jq -n '{ prefix: "http_" }' | groundcover metrics names --body-file /dev/stdin

# What labels does a specific metric have?
jq -n '{ metric: "http_request_duration_seconds" }' | groundcover metrics keys --body-file /dev/stdin

# What values does a label take?
jq -n '{ metric: "http_request_duration_seconds", key: "service" }' \
  | groundcover metrics values --body-file /dev/stdin
GCQL クイックリファレンス(ログ/トレース/イベントのクエリ)
  • 等価比較:service_name = "api"(JSON 内の二重引用符 → \")
  • 比較:duration_ms > 1000、status_code >= 500
  • ブール値:AND、OR、NOT
  • 部分文字列:message ~ "timeout"、正規表現:message ~* "^panic:"
  • メンバーシップ:level IN ("error", "fatal") — 名前付きフィールドでのみ機能します
  • フリーテキストのフレーズ: 引用符で囲んだ文字列のみを指定します。例:container = "my-service" AND "database unavailable"。フリーテキストでは IN(...) は無効です(エラー freetext 'in(...)' is not supported)— level = "error" OR level = "fatal" のように展開してください。
  • 空の query は絶対に送信しないでください — query: "" → 500 pipeline cannot be nil。必ず 1 つ以上の項を指定してください。
  • Null チェック:trace_id IS NOT NULL

フィールドの列挙:search discovery/search keys は扱いにくく(discovery には Limit と Type が必要で、それでも 400 になる場合があります)、確実な方法はサンプルログを 1 件取得して、keys と解析済みの body を調べることです。

モニターを見つけてミュートする
groundcover monitors list --query 'monitor_name ~ "ingest"'
groundcover silences create --body-json '{"monitor_id":"<id>","duration_seconds":3600,"reason":"deploy"}'
すべてのダッシュボードを出力する

リストのフィールドは id ではなく uuid です(.id は null)。各エントリーには archivedTimestamp も含まれます — アーカイブ済みのものは除外してください(アクティブなもの = 0001-01-01T00:00:00.000Z)。

groundcover dashboards list \
  | jq -r '.[] | select(.archivedTimestamp == "0001-01-01T00:00:00.000Z") | .uuid' \
  | while read id; do groundcover dashboards get "$id" > "dashboards/$id.json"; done
テンプレート変数を入力済みのダッシュボードへのディープリンクを作成する

groundcover dashboards get <uuid> は、.preset の下に変数定義を返します(JSON 文字列 — fromjson で解析します)。ダッシュボードを見つけて、その変数を確認します:

groundcover dashboards list | jq -r '.[] | select(.name|test("prod";"i")) | "\(.uuid)\t\(.name)"'
groundcover dashboards get <uuid> | jq -r '.preset | fromjson | .variables'
# each var: { kind:"list", spec:{ values:{default:["*"]}, datasource:{key,kind,metric}, variableName } }

ウェブアプリは、選択した変数の値を variables URL クエリパラメーターにエンコードします。これは $<variableName> をキーとする URL エンコード済みの JSON オブジェクトです。各エントリーには name、key、values(配列。myapp* のようなグロブをサポート)、datasource(通常は "metrics")、および refiner.metric(変数の datasource.metric にあるソースメトリック)が必要です。

必要なすべての変数を固定してください — 値を広く指定したい変数も含みます。 省略した変数は、ダッシュボードの保存済みデフォルト値にフォールバックします。この値は * とは限りません(例:ハードコードされた deployment ハッシュや shard: primary)。本当に広範囲を表示するには、該当する変数を明示的に ["*"] に設定してください。使用する前にラベルの値が存在することを必ず確認してください — たとえば、app_kubernetes_io_instance に単独の myapp はなく、myapp-web-0 などしかない場合は、myapp* のグロブを使用します。

エンコードが正しくなるよう、jq で作成します:

VARS=$(jq -cn '{
  "$cluster":{name:"cluster",key:"cluster",values:["example-cluster"],datasource:"metrics",refiner:{metric:"my_metric_total"}},
  "$deployment":{name:"deployment",key:"deployment",values:["*"],datasource:"metrics",refiner:{metric:"my_metric_total"}},
  "$app_kubernetes_io_instance":{name:"app_kubernetes_io_instance",key:"app_kubernetes_io_instance",values:["myapp*"],datasource:"metrics",refiner:{metric:"my_metric_total"}}
}')
ENC=$(jq -rn --arg v "$VARS" '$v|@uri')
echo "https://app.groundcover.com/dashboards?backendId=groundcover&tenantUUID=<your-tenant-uuid>&duration=Last+1+hour&viewId=<uuid>&qb-disable-auto-focus=true&variables=${ENC}"

注意:ダッシュボードは /dashboards/<uuid> パスではなく、viewId=<uuid> で開きます。duration には Last+1+hour/Last+5+minutes のような UI 文字列を指定します。

raw 経由でアドホックな Prom クエリを実行する
groundcover raw prometheus api query --query query='up{namespace="prod"}'

ダッシュボードの構築と編集

ダッシュボードで重要なのは CRUD 動詞(dashboards get/list/create/update/archive/restore)ではなく、パネルのレイアウト全体が 1 つのフィールドに格納される preset です。

Preset の構造

dashboards get <uuid> は、.preset が JSON 文字列のダッシュボードを返します(fromjson/json.loads で解析し、書き戻す前に文字列に再シリアライズします)。構造:

{
  "spec": { "layoutType": "ordered", "crosshairSyncEnabled": true },
  "layout": [ /* one entry per TOP-LEVEL item, placed on a 24-col grid */ ],
  "widgets": [ /* the actual panels, referenced by id from layout */ ],
  "duration": "Last 6 hours",   // UI duration string
  "variables": [ /* template vars, same shape as the deep-link recipe */ ],
  "schemaVersion": 7
}
  • layout — 最上位のグリッド配置です。各エントリーは { "id":"A", "h":12, "w":24, "x":0, "y":0, "minH":8 } です。グリッドは幅 24 列です(w:8 は 3 分の 1、w:12 は半分)。id はウィジェットの id と一致する必要があります。行を積み重ねるには y を手動で計算します — 自動配置はありません。
  • widgets — { id, name, type, queries:[{id, expr, dataType:"metrics", editorMode:"editor"}], visualizationConfig:{ type, selectedUnit, ...} } です。expr は $var 置換を含む PromQL です。
  • ウィジェットの種類:time-series、stat、text(content に Markdown を指定。クエリなし — ヘッダーや区切りとして使用)、section
セクション(折りたたみ可能なグループ)

セクションは、{ id, name, type:"section", color, isCollapsed:false } というウィジェットです。その layout エントリーには、相対位置で配置されたパネルエントリーの children 配列が含まれます:{ id, h, w:24, x:0, y:0, children:[ {h,w,x,y,id,minH}, ... ] }。ヘッダーは上部の約 2 行を占めるため、子要素は y:2 から開始します。

更新契約

dashboards update <uuid> の本文には、楽観的同時実行制御のため、currentRevision(現在の .revisionNumber)を含める必要があります。省略すると、Field validation for 'CurrentRevision' failed on the 'required_if' tag が返されます。更新に成功するたびに、次の書き込みを行う前に再度 get を実行し、更新されたリビジョンを読み取ってください。

groundcover dashboards get <uuid> > d.json
# NEW_PRESET must be the preset object re-serialized to a STRING
jq -n --slurpfile d d.json --arg preset "$NEW_PRESET" '{
  name: $d[0].name, viewType: ($d[0].viewType // "explore"),
  status: "active", currentRevision: $d[0].revisionNumber, preset: $preset
}' | groundcover dashboards update <uuid> --body-file /dev/stdin
検証ルール(API からは Dashboard validation failed としか返されません)

更新エンドポイントは、不透明な 400 {"message":"Dashboard validation failed"} を返します。フィールドも問題のあるウィジェットも示されません。このエラーが発生したら、二分探索してください。最小限のプリセット(セクション 1 つ/パネル 1 つ)をデプロイし、問題が発生するまで要素を追加していきます。特に分かりにくく、二分探索に実際かなり時間がかかるルールが 2 つあります。

  1. 統計ウィジェット(visualizationConfig.type:"stat")が検証に通るのは、トップレベルの layout エントリとしてのみです。セクションの children[] 内には決して配置できません。 時系列ウィジェットはどちらにも配置できます。概要の統計行を作るには、統計パネルをトップレベル項目として配置し(その上に text ヘッダーウィジェットを置きます)、時系列パネルはセクション内に配置してください。
  2. セクションの color に指定できるのは固定パレットのみです。 有効と確認済み:gray、purple、teal。拒否されると確認済み:green、blue、red、yellow、orange。
遅延しているメトリクスで統計パネルに「No Results」と表示される場合 → last_over_time でラップする

統計パネルは、「now」でのインスタントクエリとして評価されます。リアルタイムより遅延するメトリクスでは、そのインスタントウィンドウが空になり、時系列パネル(ウィンドウ全体を範囲クエリするため)では正常にグラフ表示されるにもかかわらず、パネルに 「No Results」 と表示されます。ポーリング型のインテグレーション(CloudWatch などのクラウドプロバイダーインテグレーションなど)から取得したメトリクスは、リアルタイムから数分遅れることがよくあるため、それらを直接使う統計パネルは空白になります。

対処法:鮮度が失われた時間より前までインスタント評価がさかのぼるように、集計の内側でセレクターを last_over_time(<selector>[30m]) でラップします。

max(last_over_time(my_metric{...}[30m]))   # NOT  max(my_metric{...})

*_over_time ラッパーは統計パネルでも正しく表示されます(例:正常に動作する 100 * avg_over_time((...)[7d:5m]) の稼働率統計)。リアルタイムでスクレイプされる(約 1 秒の鮮度)クラスター内メトリクスには必要ありません。

UI を使わずにダッシュボードを検証する

ヘッドレスブラウザーが Groundcover の SSO 画面に阻まれた場合(セッションがない場合)、スクリーンショットで検証できません。代わりに API で検証してください。

  • すべてのクエリがデータを返すこと: デプロイ済みプリセットを取得し、各 expr の値を具体的な値に置き換えます($var → 実際のラベル値、ワイルドカード変数 → =~".+" 正規表現)。そのうえで、metrics query に範囲クエリとして渡します。メトリクスの出力間隔以上の期間を指定してください(疎なインテグレーションメトリクスは、数分ごとにしか出力されない場合があります)。
  • ジオメトリ: どのレイアウト矩形も重ならず、すべての x+w ≤ 24 が成り立つことを確認します(トップレベルのエントリと各セクションの children が対象です)。
  • 注意事項: CLI ではインスタントクエリを確実に実行できないため(「よくある問題」を参照)、CLI から統計パネルのインスタントクエリ経路を再現できません。鮮度と範囲クエリのデータから推測してください。
ポーリング型インテグレーションのメトリクス(例:CloudWatch):ラベルスキームの注意点

ポーリング型のクラウドインテグレーションから取り込まれたメトリクスは、ダッシュボードを構築する際に問題となる点で、クラスター内のエクスポーターメトリクスとは異なります。

  • リアルタイムより遅延します(上記の統計パネルに関する注意を参照)。秒単位ではなく、分単位の遅延です。
  • stat ディメンション(stat=average/maximum/minimum)によって複製されることがよくあります。 各時系列が 3 倍に増えるため、必ず必要なものに絞り込んでください(例:stat="average")。そうしないと、集計で二重または三重にカウントされます。
  • 環境/スコープのラベルは、統合名に基づいており、単純な env ではありません。同じリソースがクラスター内エクスポーターでもカバーされている場合、同じ概念を表す 2 つのメトリクス群で 異なるラベルキー(例:instance_id と instanceid)が使われます。1 つの変数で両方をカバーしようとせず、ラベルスキームごとに別々のテンプレート変数を使ってください。

本番環境のオブザーバビリティに関するトリアージフロー

「本番環境で X が壊れているのはなぜ?」「サービス Y で何が起きているの?」と尋ねられた場合:

  1. 時間範囲を絞ります。 デフォルトは直近 1 時間です。date -u を使って START/END を計算します(レシピを参照)。
  2. まずログを確認します。 service_name と level = "error" でフィルタリングする GCQL フィルターを指定して、groundcover logs search を実行します。低コストで、通常はこれで答えが見つかります。
  3. レイテンシーや遅延が問題なら、トレースを確認します。 duration_ms、status_code、または service_name でフィルタリングして、groundcover traces search を実行します。いくつかの trace_id を取得し、trace_id = "..." でログに戻って確認します。
  4. 時間経過に伴う傾向を把握するにはメトリクスを確認します。 PromQL を使って groundcover metrics query を実行し、エラー率、p99、飽和度を確認します。グラフには range、単一時点の確認には instant を使います。
  5. 「そもそも稼働しているのか」を確認するには、K8s を確認します。 groundcover k8s workloads でステータスや再起動を確認し、groundcover k8s events-search で Warning イベント(OOMKilled、FailedScheduling、BackOff)を確認します。
  6. フィールド名がわからない場合: groundcover search discovery、metrics names、metrics keys、metrics values で一覧を取得します。
  7. インシデント中にノイズの多いアラートを一時停止する必要がある場合: groundcover monitors list --query … → groundcover silences create を実行します。

どのコマンドがあるかわからない場合

  1. 上記のリソース一覧を確認します。
  2. groundcover --help と groundcover <resource> --help を実行します。
  3. raw の場合:groundcover raw list を実行し、次に groundcover raw list <group> を実行します。

よくある問題

401 Unauthorized、トークンのプレフィックス/長さに関するエラー、または結果が空になる
  • Invalid token prefix/Invalid token length → キーが gcsa_ のサービスアカウントキーではありません(認証を参照)。よくある間違いは、gcik_ のインジェストキーを使うことです。
  • 有効に見える gcsa_ キーで 401 が発生する → キーが別のテナント用です。他のテナントの場合は、GROUNDCOVER_TENANT_UUID と(該当する場合は)GROUNDCOVER_BASE_URL も設定します。
  • それ以外の場合は、現在のシェルで環境変数が実際にエクスポートされていることを確認します。
SDK コマンドでボディが拒否される

ボディの形式が SDK のコントラクトと合っていません。get <id> で既存のリソースを取得し、その形式をテンプレートとして使います。

logs search/traces search/events-search の結果が空になる

ほとんどの場合、次のいずれかが原因です。

  • 時間範囲が正しくない/狭すぎます。start は end より前で、どちらも RFC 3339 UTC 形式である必要があります。
  • GCQL のフィールド名がこのテナントに存在しません。search discovery/search keys を使って一覧を取得します。
  • クエリー文字列がエスケープされていません。JSON 内では、service_name = "api" は "service_name = \"api\"" となります。
メトリクスが存在するのに metrics query でデータが返らない
  • フィールド名は大文字で始まります(Promql、Start、End、Step、QueryType)。小文字でも JSON としては受け入れられますが、無視されます。
  • Step は数値ではなく文字列("60")です。
  • インスタントクエリーの場合は "QueryType": "instant" を設定し、Step を省略します。確認されている注意点: テストでは、新しいメトリクスであっても、あらゆる形式(Start==End、Time、QueryType の有無)で CLI の metrics query が 400 metricsQueryBadRequest を返しています。現在の値を 1 つだけ取得する必要がある場合は、短い時間範囲を対象にした範囲クエリー(QueryType:"range" + Step)に切り替え、最後のポイントを使います。(本来のインスタント PromQL は raw prometheus api query からも実行できますが、このパススルーでは metrics query とは異なるストアを対象にする場合があります。)
  • レスポンスの解析:結果は .data.result // .result にあり、各 values エントリーは [unix_ts, "stringvalue"] です。範囲の合計は [.values[][1]] | map(tonumber) | add で計算し、タイムスタンプは strftime でフォーマットします。
logs search がタイムアウトする(context deadline exceeded)

ログの多い高ボリュームなワークロードではログが大量に発生するため、広い範囲や単一 Pod のクエリーでも、約 60〜90 秒の時間範囲でタイムアウトすることがあります。対処方法:

  • Pod 名だけでなく、必ず識別に役立つ語句(フレーズ + container/pod)を含めます。
  • 時間範囲を狭め、--timeout を延長します(例:--timeout 120s)。
  • 1 つのクエリーに大きな OR の連鎖を含めるのは避け、個別に実行します。
  • 「頻度はどのくらいか/時間とともにどう変化するか」という質問には、ログの収集よりも**metrics query** を優先します。
monitors の編集と検索
  • monitors get / update は YAML を使用します(--raw を指定した場合も同様です)。手順:monitors get <uuid> > mon.yaml を実行し、編集してから monitors update <uuid> --body-file mon.yaml を実行します。更新が成功すると {"status":202} が返されます(非同期で適用されるため、再度 get を実行して確認してください)。
  • Slack-app の宛先には、connectedApps: [<app-id>] と connectedAppParams.<app-id>.channels: [{id, name}] の両方が必要です。webapp の PUT は、この形式の YAML を text/plain として送信します。SDK ≥ v1.376 では connectedAppParams がエンコードされますが、それより古い SDK ではこの項目が欠落し、API は 400 connectedApps[0]: channels is required for slack-app route params を返します。
  • モニターのモデルは model.queries[].sqlPipeline.filters.conditions[] にあります。各条件は {key, origin: root, type, filters:[{op, value}]} です。フリーテキスト検索では type: freetext と op: phrase_search を使用します。その他の設定項目:instantRollup(例:1 minute)、thresholds[]、evaluationInterval.{interval, pendingFor}。
  • monitors list --query 'monitor_name ~ "..."' → 400 regexp requires a string column type。monitor_name = "exact" を使用するか、すべてを一覧表示して jq で絞り込んでください。
グループ内での Raw コマンドの「not found」

そのエンドポイントは、取得した HAR に含まれていません。対応する SDK 形式があればそれを使用するか、再生成してください。再生成の処理は groundcover-cli リポジトリにあります(go run ./scripts/generate-commands.go <har>)。

コメント