logql-generator について
logql-generator は、Loki ログ向けの LogQL クエリを作成する対話型スキルです。クエリ、ダッシュボード、アラート、トラブルシューティングに対応し、要件とバージョンを段階的に確認して互換性に配慮した結果を生成します。
主な機能
- 01クエリ目標とログ情報の段階的な収集
- 02Loki と Grafana のバージョンに応じた構文
- 03クエリ計画と最終版・段階版の出力
- 04複雑なクエリの参照資料チェック
- 05実行方法と互換性に関する説明
活用シーン
- 01サービスの Loki エラー率クエリ作成
- 02LogQL アラート式の作成
- 03障害調査の要件をログクエリに変換
- 04Loki ログからダッシュボード指標を作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ akin-ozer/ cc-devops-skills --skill logql-generatorインストール後、Claude Code で/logql-generatorを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
examples/common_queries.logqlreferences/best_practices.mdscripts/run_regression_checks.shtests/test_loki_runtime_integration.pytest_skill_contract.py詳細
LogQL クエリジェネレーター
概要
本番環境で使える LogQL クエリを生成するための対話型ワークフローです。LogQL は Grafana Loki のクエリ言語で、インデックス付きのラベル選択、ログ行のフィルタリング、解析、メトリクス集計に対応しています。
トリガーのヒント
- 「サービス別のエラー率を求める LogQL クエリを書いてください。」
- 「Loki のアラートクエリの作成を手伝ってください。」
- 「このトラブルシューティング要件を LogQL に変換してください。」
- 「LogQL クエリの作成を段階的に進めたいです。」
クエリの生成、ダッシュボードクエリ、アラート式、Loki ログを使ったトラブルシューティングに、このスキルを使用してください。
実行フロー(決定論的)
必ず各ステージを順番に実行してください。必須ステージを省略しないでください。
ステージ 1(必須):意図の確認
AskUserQuestion を使用して、目的とユースケースを確認してください。
テンプレート:
- 「主な目的は何ですか:デバッグ、アラート、ダッシュボードのメトリクス、調査のいずれですか?」
- 「必要なのはログクエリ(生のログ行)ですか、それともメトリクスクエリ(数値の出力)ですか?」
- 「対象の時間範囲はどれくらいですか(例:直近 15m、1h、24h)?」
AskUserQuestion が利用できない場合の代替方法:
- 同じ質問をプレーンテキストで尋ねて、続行してください。
ステージ 2(必須):ログソースの詳細確認
以下を収集してください:
- ストリームセレクター用のラベル(
job、namespace、app、service_name、cluster) - ログ形式(JSON、logfmt、プレーンテキスト、混在)
- フィルタリング/集計に使う既知のフィールド(
status、level、duration、path、trace_id)
不明瞭な回答や不完全な回答への対応:
- 必須フィールドが不足している場合は、焦点を絞った追加質問を 1 つ行ってください。
- それでも不足している場合は、明示的な前提を置いて進めてください。
- ユーザーがすぐに修正できるよう、出力では前提に
Assumptions:を付けてください。
ステージ 3(必須):Loki と Grafana のバージョン確認
以下を収集または推定してください:
- Loki のバージョン(例:
2.9.x、3.0+、不明) - Grafana のバージョン(例:
10.x、11.x、不明) - デプロイ環境(セルフホストの Loki、Grafana Cloud、不明)
バージョン互換性の方針:
- バージョンが判明している場合は、互換性のある最新の構文のみを使用してください。
- バージョンが不明の場合は、互換性を優先した構文を使用し、デフォルトでは 3.x 専用の機能を避けてください。
- バージョンが不明な場合は、任意で使用できる「3.x 最適化版」を別途提示してください。
バージョンが不明な場合、デフォルトで以下を避けてください:
- パターンマッチ演算子
|>と!> approx_topk- 構造化メタデータ固有の動作(
detected_level、高速化されたメタデータフィルタリングに関する前提)
ステージ 4(必須):計画の確認と出力モード
平易な英語で計画を提示し、その後、ユーザーに出力モードを選んでもらってください。
計画テンプレート:
LogQL Query Plan
Goal: <goal>
Query type: <log or metric>
Streams: <selector>
Filters/parsing: <filters + parser>
Aggregation window: <function and [range]>
Compatibility mode: <version-aware or compatibility-first>
モード選択テンプレート:
- 「
final query only(デフォルト)とincremental build(段階的な作成)のどちらにしますか?」
ユーザーが選択しない場合は、final query only をデフォルトにしてください。
ステージ 5(条件付き、ブロッキング):複雑なクエリのリファレンス確認
複雑なクエリに該当する条件:
- ネストされた集計(
topk(sum by(...))、複数のsum by、パーセンタイル) - パフォーマンスに注意が必要なクエリ(大量のストリーム、長い時間範囲)
- アラート式
- テンプレート関数(
line_format、label_format) - 正規表現を多用した抽出、IP マッチング、パターン解析
- Loki 3.x の機能を使用する場合
ブロッキングチェックポイントのルール:
- 生成する前に、明示的なファイルを開く/読み取る操作を行い、関連ファイルを確認してください。
- 最低限必要なファイル:
examples/common_queries.logql(構文とクエリのパターンを確認するため)references/best_practices.md(パフォーマンスとアラートに関するガイダンスを確認するため)
- このチェックポイントを完了するまで、最終クエリを生成しないでください。
ファイル読み取りツールが利用できない場合の代替方法:
- この環境ではリファレンスファイルを読み取れなかったことを伝えてください。
- 保守的なクエリ(互換性を優先し、よりシンプルな演算子を使用)を生成してください。
- 結果に
Unverified against local referencesと明記してください。
ステージ 6(条件付き):外部ドキュメントの参照ポリシー(WebSearch より Context7 を優先)
バージョン固有の動作、不明確な構文、またはローカルのリファレンスに記載されていない高度な機能に限り、外部参照を使用してください。
確認の優先順位:
- まず Context7:
libraryName="grafana loki"を指定してmcp__context7__resolve-library-id- 正確なトピックについて
mcp__context7__query-docs
- 次に WebSearch(以下の場合のみフォールバックとして使用):
- Context7 を利用できない
- Context7 に必要なバージョン固有の詳細がない
- 最新リリースや非推奨化の確認が必要
WebSearch のフォールバックに関する制約:
- Grafana/Loki の公式ドキュメントとリリースノートを優先してください。
- フォールバック検索に基づく記述がどれかを明記してください。
ステージ 7(必須):クエリの生成
ステージ 7A(デフォルト):最終クエリのみ
本番環境ですぐに使えるクエリを 1 つと、簡潔な説明を返してください。
ステージ 7B(任意):段階的な構築モード
依頼された場合、または複雑なパイプラインのデバッグ時に使用してください。
段階的なテンプレート:
- ストリームセレクター
- 行フィルター
- パーサー
- 解析済みフィールドのフィルター
- 集計/ウィンドウ
ステージ 8(必須):使い方と確認事項の提示
必ず以下を含めてください:
- 最終クエリまたは段階的な手順
- 実行方法(Grafana Explore/パネルまたは
logcli) - 調整可能な項目(ラベル、しきい値、範囲)
- 前提条件と互換性に関する注意事項
AskUserQuestion のテンプレート
初回確認用テンプレート
- 「このクエリの対象となるシステム/サービスは何ですか?」
- 「ストリームの選択に信頼できるラベルはどれですか?」
- 「何を一致条件としますか(エラーテキスト、ステータスコード、レイテンシーのしきい値、ユーザーパスなど)?」
- 「出力は生ログですか、それともアラート/ダッシュボード用のメトリクスですか?」
バージョン確認用テンプレート
- 「実行している Loki のバージョンは何ですか?」
- 「使用している Grafana のバージョンは何ですか?」
- 「不明な場合は、互換性を優先したクエリを生成し、オプションとして 3.x 向けの変形も追加しますか?」
曖昧さの確認用テンプレート
- 「
<field>が不明です。続行できるように<default>と仮定してもよいですか?」
基本パターン
ストリームの選択とフィルタリング
{job="app"} |= "error" |= "timeout"
{job="app"} |~ "error|fatal|critical"
{job="app"} != "debug"
解析
{app="api"} | json | level="error" | status_code >= 500
{app="api"} | logfmt | caller="database.go"
{job="nginx"} | pattern "<ip> - - [<_>] \"<method> <path>\" <status> <size>"
メトリクスの集計
rate({job="app"} | json | level="error" [5m])
sum by (app) (count_over_time({namespace="prod"} | json [5m]))
sum(rate({app="api"} | json | level="error" [5m])) / sum(rate({app="api"}[5m])) * 100
quantile_over_time(0.95, {app="api"} | json | unwrap duration [5m])
topk(10, sum by (error_type) (count_over_time({job="app"} | json | level="error" [1h])))
フォーマットと IP の照合
{job="app"} | json | line_format "{{.level}}: {{.message}}"
{job="app"} | json | label_format env=`{{.environment}}`
{job="nginx"} | logfmt | remote_addr = ip("192.168.4.0/24")
クエリ構築ルール
- 具体的なストリームセレクターを使用してください(インデックス付きラベルを優先)。
- フィルターは次の順序を優先してください:行フィルター -> 解析 -> 解析済みフィールドのフィルター。
- パーサーのコスト順は
pattern>logfmt>json>regexpを優先してください。 - Loki のバージョンが不明な場合は、互換性を優先した構文を使用してください。
- 複雑または重要なクエリでは、最終出力の前にステージ 5 のチェックポイントを完了してください。
高度なテクニック
複数のパーサー
{app="api"} | json | regexp "user_(?P<user_id>\\d+)"
数値メトリクス用の Unwrap
sum(sum_over_time({app="api"} | json | unwrap duration [5m]))
パターン照合演算子(Loki 3.0 以降、正規表現より 10 倍高速)
{service_name=`app`} |> "<_> level=debug <_>"
論理演算子
{app="api"} | json | (status_code >= 400 and status_code < 500) or level="error"
Offset 修飾子
sum(rate({app="api"} | json | level="error" [5m])) - sum(rate({app="api"} | json | level="error" [5m] offset 1d))
ラベル操作
{app="api"} | json | keep namespace, pod, level
{app="api"} | json | drop pod, instance
注:LogQL には
dedupまたはdistinct演算子がありません。プログラムによる重複排除には、sum by (field)などのメトリクス集計を使用してください。
Loki 3.x の主な機能
構造化メタデータ
インデックス化せずにカーディナリティの高いデータ(trace_id、user_id、request_id)を扱えます:
# Filter AFTER stream selector, NOT in it
{app="api"} | trace_id="abc123" | json | level="error"
クエリの高速化(Bloom Filters)
構造化メタデータのフィルターはパーサーの前に配置してください:
# ACCELERATED
{cluster="prod"} | detected_level="error" | logfmt | json
# NOT ACCELERATED
{cluster="prod"} | logfmt | json | detected_level="error"
approx_topk(確率的)
approx_topk(10, sum by (endpoint) (rate({app="api"}[5m])))
アラート用の vector()
sum(count_over_time({app="api"} | json | level="error" [5m])) or vector(0)
自動ラベル
- service_name:コンテナー名から自動入力されます
- detected_level:
discover_log_levels: trueの場合に自動検出されます(構造化メタデータとして保存されます)
関数リファレンス
ログ範囲の集計
| 関数 | 説明 |
|---|---|
rate(log-range) | 1 秒あたりのエントリー数 |
count_over_time(log-range) | エントリー数 |
bytes_rate(log-range) | 1 秒あたりのバイト数 |
bytes_over_time(log-range) | 時間範囲内の合計バイト数 |
absent_over_time(log-range) | ログがない場合に 1 を返します |
ルール:
- 生ログのバイト量には
bytes_over_time(<log-range>)を使用してください。 - ログ内容から抽出した数値のバイトフィールドには、アンラップされた範囲集計とともに
| unwrap bytes(field)を使用してください。
アンラップ範囲集計
| 関数 | 説明 |
|---|---|
sum_over_time, avg_over_time, max_over_time, min_over_time | 数値を集計します |
quantile_over_time(φ, range) | φ 分位数(0 ≤ φ ≤ 1) |
first_over_time, last_over_time | 区間内の最初/最後の値 |
stddev_over_time | アンラップされた値の母標準偏差 |
stdvar_over_time | アンラップされた値の母分散 |
rate_counter | 値を単調増加するカウンターとして扱った、1 秒あたりのレート |
集計演算子
sum, avg, min, max, count, stddev, topk, bottomk, approx_topk, sort, sort_desc
グループ化する場合:sum by (label1, label2) または sum without (label1)
変換関数
| 関数 | 説明 |
|---|---|
duration_seconds(label) | 期間文字列を変換します |
bytes(label) | バイト文字列(KB、MB)を変換します |
label_replace()
label_replace(rate({job="api"} |= "err" [1m]), "foo", "$1", "service", "(.*):.*")
パーサーリファレンス
logfmt
| logfmt [--strict] [--keep-empty]
--strict:形式が不正なエントリでエラーにします--keep-empty:単独のキーを保持します
JSON
| json # All fields
| json method="request.method", status="response.status" # Specific fields
| json servers[0], headers="request.headers[\"User-Agent\"]" # Nested/array
pattern
| pattern "<ip> - - [<timestamp>] \"<method> <path> <_>\" <status> <size>"
名前付きプレースホルダーは抽出されたラベルになります。<_> はフィールドを破棄します。
regexp
| regexp "(?P<level>\\w+): (?P<message>.+)"
名前付きキャプチャグループ(?P<name>)を使用します。pattern/logfmt/json より低速です。
decolorize
| decolorize
ANSI カラーエスケープコードを除去します。ログがターミナル出力から取得される場合は、解析前に適用してください。
unpack
| unpack
Promtail の pack パイプラインステージでパックされたログエントリを展開します。元のログ行と、埋め込まれたラベルを復元します。
テンプレート関数
line_format と label_format で使用する一般的な関数:
文字列:trim, upper, lower, replace, trunc, substr, printf, contains, hasPrefix
数学:add, sub, mul, div, addf, subf, floor, ceil, round
日付:date, now, unixEpoch, toDate, duration_seconds
正規表現:regexReplaceAll, count
その他:fromJson, default, int, float64, __line__, __timestamp__
詳しい使用方法については、examples/common_queries.logql を参照してください。
アラートルール
# Alert when error rate exceeds 5%
(sum(rate({app="api"} | json | level="error" [5m])) / sum(rate({app="api"}[5m]))) > 0.05
# With vector() to avoid "no data"
sum(rate({app="api"} | json | level="error" [5m])) or vector(0) > 10
エラー処理
| 問題 | 解決策 |
|---|---|
| 結果がない | ラベルが存在することを確認し、時間範囲を検証して、ストリームセレクター単独でテストします |
| クエリが遅い | 具体的なセレクターを使用し、解析前にフィルターを適用して、時間範囲を短くします |
| 解析エラー | ログ形式がパーサーと一致することを確認し、JSON の妥当性をテストします |
| カーディナリティが高い | 一意の値にはラベルフィルターではなく行フィルターを使用し、集計します |
ドキュメントの検索
Stage 6 のポリシーを使用します。次の場合は外部ドキュメントを検索します。
| トリガー | 検索するトピック | 使用するツール |
|---|---|---|
| ユーザーが Loki 3.x の機能に言及 | structured metadata, bloom filters, detected_level | まず Context7 |
approx_topk 関数が必要 | approx_topk probabilistic | まず Context7 |
パターンマッチ演算子(|>, !>) | pattern match operator | まず Context7 |
アラート用の vector() 関数 | vector function alerting | まず Context7 |
| レコーディングルールの設定 | recording rules loki | まず Context7 |
| 構文やエッジケースが不明 | 特定の関数/演算子 | まず Context7 |
| バージョン固有の動作に関する質問 | バージョン + 機能 | WebSearch にフォールバック |
| Grafana Alloy の統合 | grafana alloy loki | WebSearch にフォールバック |
リソース
examples/common_queries.logql:クエリパターン、テンプレート関数の例references/best_practices.md:最適化、アンチパターン、アラートに関するガイダンス
フローの例
例 A:最終クエリのみ(デフォルト)
- ユーザーが、15 分間のサービス別 5xx 率を尋ねます。
- ラベルを取得し、形式を指定します(
json)。 - バージョンとモード(
final query only)を確認します。 - クエリを 1 つ生成します:
sum by (service) (rate({namespace="prod", app="api"} | json | status_code >= 500 [15m]))
例 B:段階的な構築(任意)
- ユーザーがログイン失敗のデバッグを依頼し、段階的なモードを求めます。
- 段階的な構築を提示します:
{app="auth"}
{app="auth"} |= "login failed"
{app="auth"} |= "login failed" | json
sum(count_over_time({app="auth"} |= "login failed" | json [5m]))
- いずれかのステップで結果が 0 件になった場合、どこで停止すべきかを説明します。
完了条件
以下のすべてのチェックに合格した場合にのみ、タスクを完了とします。
- 必須のステージ(1、2、3、4、7、8)が完了していること。
- 複雑なクエリでは、ステージ 5 のチェックポイントが完了していること。
- 外部ドキュメントが必要な場合、ステージ 6 の検索順序として WebSearch より先に Context7 を使用していること。
- 出力モードを明示的に選択しているか、デフォルト(
final query only)を使用していること。 - バージョンが不明な場合、Loki/Grafana の互換性に関する前提を明記していること。
- 最終出力にクエリテキスト、使用上の注意、調整可能な項目、前提が含まれていること。
バージョンに関する注意
- Loki 3.0+:ブルームフィルター、構造化メタデータ、パターンマッチ演算子(
|>,!>) - Loki 3.3+:
approx_topk関数 - Loki 3.5+:Promtail は非推奨(Grafana Alloy を使用)
- Loki 3.6+:水平スケーラブルなコンパクター、Grafana プラグインとしての Loki UI
非推奨:Promtail(Alloy を使用)、BoltDB ストア(v13 スキーマを使用した TSDB に置き換え)