Claude Media
Grafana LokiのログをClaudeで検索する — LogQLを書かない運用

Grafana LokiのログをClaudeで検索する — LogQLを書かない運用

mcp-grafanaのLokiツールで、LogQLを直接書かずにログ検索・ラベル調査・ラベル戦略監査を行う手順と、クエリコストを抑えるガードレール設定です。

障害調査の途中でLogQLの文法を思い出しながらログを絞り込むのは、地味に時間を食います。mcp-grafanaのLokiツールを使うと、「過去30分でエラーレベルのログを絞り込んで」という自然言語の指示から、Claude CodeがLogQLクエリを組み立ててGrafanaのLokiデータソースに投げます。ラベル設計の監査ツール(analyze_loki_labels)まで揃っているのが、ダッシュボード操作系のツールとの違いです。

Loki Queryingツールでできること

mcp-grafanaのLokiカテゴリは6つのツールで構成されます。ログクエリとメトリッククエリ両方に対応するquery_loki_logs、利用可能なラベル名の一覧を返すlist_loki_label_names、特定ラベルの値一覧を返すlist_loki_label_values、ログストリームの統計情報を返すquery_loki_stats、検出済みのログパターンを返すquery_loki_patterns、そしてラベル戦略を監査するanalyze_loki_labelsです。設定カテゴリには、Alloyのloki.process設定スニペットを生成するsuggest_loki_alloy_label_configもあります。

Claude Codeでの有効化

インストールとRBACスコープ設計の全体はmcp-grafanaの導入とRBAC設計を参照してください。Lokiツールは既定で有効なカテゴリです。ログ調査用のサービスアカウントを分けるなら、対象のLokiデータソースUIDにスコープを絞り込みます。

claude mcp add-json grafana-loki \
  '{"command":"uvx","args":["mcp-grafana","--enabled-tools","loki,datasource,search"],"env":{"GRAFANA_URL":"https://myinstance.grafana.net","GRAFANA_SERVICE_ACCOUNT_TOKEN":"<サービスアカウントトークン>"}}'

LogQLを書かずにログを検索する

query_loki_logsはログクエリとメトリッククエリの両方を実行できます。「〇〇サービスの過去1時間のエラーログを見せて」と頼めば、Claudeがラベルセレクタとフィルタを組み立ててLogQLとして実行します。1回のクエリで返す行数の上限は--max-loki-log-limit(既定100件)で制御でき、Loki側のmax_entries_limit_per_queryより1以上小さい値にしておくと、結果が切り詰められたことをツール側で検出できます。

Claudeが組み立てるLogQLの読み方

LogQLのクエリは、必ずログストリームセレクタ({...})から始まります。その後ろに、行フィルタやパーサーをつなぐパイプラインを置けます。Claudeが返すクエリもこの形なので、骨格が分かれば内容を確かめられます。

{namespace="prod", app="api"} |= "error" != "timeout" | json
  • {namespace="prod", app="api"}: 対象のストリームを決めるセレクタ。ラベルの一致条件には=・!=・=~・!~が使えます
  • |= "error": 「error」を含む行だけを残す行フィルタ。!=は含む行を除き、|~は正規表現で絞ります
  • | json: 各行のJSONを解析してラベルとして取り出し、以降のラベル条件で絞れるようにします

行フィルタはパーサーより前に置くほうが速く動きます。Claudeの出したクエリが遅いときは、この順序と、セレクタが広すぎないかを見ます。

ラベル一致の=~と!~は完全一致(前後を固定)で評価され、行フィルタの|~と!~は部分一致です。同じ=~でも、{name=~"mysql.+"}は前後が固定されますが、|~ "mysql"は行の途中にあれば一致します。

返ってくる結果の読み方

指示で何も指定しないと、query_loki_logsは直近1時間を新しい順(backward)に、10件まで返します。--max-loki-log-limitの100件はlimitに指定できる上限であって、既定の件数ではありません。時間範囲はstartRfc3339とendRfc3339にnow-1hのような相対表記でも渡せます。

件数を数えたいときは、ログクエリではなくcount_over_time()のメトリッククエリをqueryTypeにinstantを指定して実行します。query_loki_statsのentriesはチャンクのインデックス項目数で、条件に合う行数ではありません。

返却JSONのmetadataにはlinesReturned・maxLinesAllowed・resultsTruncated・totalLinesScannedが入ります。resultsTruncatedがtrueなら、条件に合う行がまだ残っています。以前は上限に達しても何も知らせずに打ち切られていて(GitHub issue #557)、Pod障害の調査で、起動直後の大量ログが上限を埋めて肝心の後半が見えない例が報告されていました。

広く取るときはcompact形式を使う

formatにcompactを指定すると、同じラベルの組をもつ行がストリーム単位にまとまり、ラベルを行ごとに繰り返さなくなります。レスポンスのサイズが大きく減ります。ラベルのメタデータ込みで50〜100行が100KB超になった例が、issue #761に報告されています。

くらべる

full と compact の返し方

1行ずつ

full(既定)

全行がそれぞれ自分のラベルとメタデータをもちます。サイズは大きくなりますが、どの行がどのPodのものかを行単位で追えます。

ストリーム単位

compact

ラベルの組ごとに1回だけストリームの見出しを出し、行は本文を並べます。ストリーム内で値が変わらない構造化メタデータは見出しに、行ごとに変わるものは行側に置かれます。

構造化メタデータ(pod・node・detected_levelなど、ストリームラベルではない項目)は、以前のcompactでは全部落ちていました。「どのPodが失敗しているか」に答えられなくなる不具合として1.4.2で再現が報告され(issue #1195)、2026年9月17日に直す変更がマージされています。古いバージョンのサーバーを使っている場合は、fullのまま使うか、更新後の動作をいちど確かめてください。

ラベルを調べる

どんなラベルで絞り込めるか分からないときはlist_loki_label_namesでラベル名の一覧を、list_loki_label_valuesで特定ラベルが取りうる値を確認します。Prometheusの同種ツールと同じ発想で、クエリを組み立てる前段としてラベル空間を把握する用途に使います。どちらも既定では全ストリームを対象にしますが、matcherに{namespace="prod"}のようなセレクタを渡せば、そのストリームの範囲だけで一覧を作れます。「prodの名前空間に出てくるserviceの値」のような問いを、全件を取ってから絞る手間なしに投げられます。時間範囲を省くと直近1時間が対象です。

ログ量とパターンを把握する

query_loki_statsはログストリームの統計(ストリーム数・チャンク数・バイト数)を返します。query_loki_patternsは検出済みのログパターンを返し、大量のログの中から共通の構造や異常なパターンを見つける用途に向きます。query_loki_statsはインデックスの統計、query_loki_patternsは検出済みパターンを返すツールで、どちらもログ本文そのものは返しません。ストリームにデータがあるかを安く確かめるには、まずquery_loki_statsを使えます。ただしentriesはチャンクのインデックス項目数で、ログの行数ではありません。条件に合う正確な行数はcount_over_time()で取ります。

Loki自体は、行フィルタを伴わないログクエリに対してmax_query_bytes_readを強制しません。ラベルセレクタが広く時間範囲も長いクエリは、テラバイト単位のスキャンになり得ます。

ラベル戦略を監査する

ログの絞り込みが遅い、ラベルの種類が多すぎて把握できない、といった悩みにはanalyze_loki_labelsが使えます。稼働中のLokiに対してライブでラベル戦略を監査することも、静的な設定を渡して監査することもでき、オプションでクエリのパフォーマンス診断まで行います。カーディナリティ(ラベル値のばらけ具合)が高すぎるラベル設計は、Lokiのインデックスサイズとクエリ速度の両方を悪化させるため、新しいログ収集を始める前に一度確認しておく価値があります。

監査の結果、承認済みのラベルだけを付与する設定に直したいときはsuggest_loki_alloy_label_configが使えます。Grafana Alloyのloki.processステージ向けの設定スニペットを生成するツールで、RBAC権限は不要です。ログ収集エージェント側の設定変更まで、Claudeとの対話だけで叩き台を作れます。

クエリのコストを抑えるガードレール

広いクエリをLoki自体は止めないので、その制御を担うのが--loki-guardrail-modeで、query_loki_logsに対するコストガードレールとして働き、既定はoffです。選択的なストリームセレクタを要求し、時間範囲の上限を課し、実行前にLokiのインデックス・統計APIでバイト数を見積もってから実行するかどうかを判断します。

ツールの説明文には、ガードレールが見ているものも明記されています。クエリのコストは走査するバイト数で、決まるのはストリームセレクタと時間範囲だけです。|=のような行フィルタや| jsonのパーサーは返す量を減らすだけで、走査量は減りません。そのため、{}・=~".*"・=~".+"・否定だけのマッチャーは選択的なセレクタとみなされず、肯定のラベルマッチャーを1つ以上含める必要があります。

モード挙動
off(既定)挙動ガードレールを適用しない
shadow挙動ブロック対象になるクエリをログに記録しつつ、そのまま実行する(インデックス・統計API呼び出しのコストは発生)
enforce挙動条件を満たさないクエリを拒否し、書き換えのヒントをモデルに返す

しきい値は--loki-guardrail-max-bytes(既定100GiB、0で無効化)と--loki-guardrail-max-range(既定24時間、[30d]のようなレンジベクターの期間も含めて計算、0で無効化)で調整します。段階的に導入するなら、まずshadowでどのクエリが引っかかるかを観察してからenforceへ切り替える運用が安全です。VictoriaLogsのデータソースでは、括弧付きセレクタ({...})の形をしたクエリだけがガードレールの対象になり、セレクタなしの素のLogsQL構文は素通りします(安価なインデックス見積もりができないため)。

ガードレールの状況を監視する

--loki-guardrail-modeを有効にした運用では、Prometheusメトリクスエンドポイント(--metrics)を有効にすると、ガードレールの判定結果を示すカウンターが追加されます。メトリクスが取れるのはSSEかstreamable HTTPのトランスポートのときだけで、この記事のuvxで起動するstdio構成では出力されません。メトリクスを見るなら、サーバーを-t streamable-httpのような形で常駐させます。

  • mcp_loki_guardrail_admitted_total — 全チェックを通過したクエリ
  • mcp_loki_guardrail_would_block_total — shadowモードでブロック対象になったが実行されたクエリ
  • mcp_loki_guardrail_blocked_total — enforceモードで拒否されたクエリ
  • mcp_loki_guardrail_fail_open_total — 評価できずそのまま通過したクエリ

いずれもbackend(loki / victorialogs / unknown)のラベルを持ち、would_blockとblockedには理由を示すreason(selector / range / bytes)、fail_openにはcause(unparseable / estimate_failed)も付きます。複数のチェックに同時に引っかかったクエリは、セレクタ→レンジ→バイト数の順で最初に引っかかった理由だけがカウントされます。

shadowからenforceへ切り替える前の見方は次のとおりです。影響を受けるクエリの規模はsum(rate(mcp_loki_guardrail_would_block_total[5m]))、reason別の内訳はsum by (reason)で出します。selectorが多数を占めるなら、--loki-guardrail-max-rangeや--loki-guardrail-max-bytesを緩めても通るようにはなりません。セレクタのチェックは無条件で効くためです。

would_blockが静かなのは、fail_open_totalも低いときだけ「ブロック対象なし」を意味します。backend="loki"でcause="unparseable"が多いなら、ガードレールがそのクエリの形を解釈できていません。VictoriaLogsでは括弧なしのLogsQLが通常の形なので、unparseableが多いのは想定内です。

特定の名前空間だけに絞り込む

Grafana OSSにはデータソース単位・ユーザー単位のラベルアクセス制御が無いため、機微な情報を含むログストリームを閲覧させたくない場合は--loki-enforced-matchersでMCPサーバー自体に制限をかけます。指定したLogQLラベルマッチャーが、サーバーが発行するすべてのネイティブLokiクエリにAND条件として追加されます。

# prod / staging環境だけを許可(許可リスト)
uvx mcp-grafana --loki-enforced-matchers 'environment=~"prod|staging"' --disable-api
 
# vault / payments名前空間を除外
uvx mcp-grafana --loki-enforced-matchers 'namespace!~"vault|payments"' --disable-api

Lokiはセレクタ内のマッチャーをAND条件で評価するため、ユーザー側のクエリは強制されたマッチャーの範囲を狭める方向にしか動けません。ポリシーと矛盾するセレクタ(除外設定下で{namespace="vault"}を指定するなど)は、単に結果が空になります。適用範囲はquery_loki_logs・query_loki_stats・query_loki_patterns・list_loki_label_names・list_loki_label_valuesの5つです。

この制限は「フェイルクローズ」で動作し、マッチャーとして解釈できないクエリはフィルタなしで送るのではなく拒否されます。ただしVictoriaLogsのデータソースはLogsQLを安全に書き換えられないため、--loki-enforced-matchersを有効にすると丸ごと拒否されます。

制限を効かせるには他の経路も止める: --loki-enforced-matchersはLokiクエリツールにしか効きません。ほかのツールにはLokiのログへ届く経路があり、止めないと制限は画面上だけ効いているように見えて、別ルートから抜けられます。

迂回

塞ぐ経路と対応するフラグ

  • --disable-api

    grafana_api_requestはLokiデータソースのプロキシへ直接クエリを投げられます。完全な迂回になるので必須です。

  • --disable-rendering

    get_panel_imageはLokiパネルをサーバー側で画像にします。ログ行は制限なしで写ります。

  • --disable-assistant

    ask_assistantはGrafana Assistantに処理を任せ、Assistantは全ストリームを読めます。書き込みツールが有効なときだけ登録されるので、--disable-writeでも塞げます。

  • --disable-snapshot

    ダッシュボードのスナップショットには、制限の外で取られたログパネルのデータが埋め込まれることがあります。

run_panel_queryは強制済みのクエリ経路を再利用するので迂回になりません。Tempoのツールが引くのはトレースで、ログの迂回にはなりません。

メトリクスとログの使い分け

mcp-grafanaはPrometheus向けのツール群(query_prometheus、list_prometheus_label_namesなど)も持っていて、Lokiのツールとよく似た構成になっています。両者の境界は「数値の推移を追うか、テキストの中身を読むか」です。エラー率の急増をダッシュボードで検知したあと、原因になっている具体的なログ行を追うのがLokiツールの役割で、Prometheusツールが返す集計値だけでは分からない詳細をここで埋めます。

ツール名の対応も揃っていて、list_prometheus_label_namesとlist_loki_label_names、list_prometheus_label_valuesとlist_loki_label_valuesのように、同じ発想のツールがデータソースごとに用意されています。障害調査での使い順は次のとおりです。

調査

Lokiで原因のログに近づく順序

  1. 1

    Prometheusで異常を数値として確かめる

    エラー率や遅延の急増が起きた時間帯を特定します。

  2. 2

    ラベルで範囲を決める

    list_loki_label_namesとlist_loki_label_valuesにmatcherを添え、対象のストリームを絞ります。

  3. 3

    量を見積もる

    query_loki_statsのバイト数とチャンク数を見て、この範囲でログを引いて重くならないかを判断します。

  4. 4

    狭い範囲でログを引く

    短い時間範囲と小さいlimitから始めます。resultsTruncatedがtrueなら、時間窓をずらすか条件を足してから次へ進みます。

よくあるつまずき

--disable-queryを付けても統計とパターンは残る: query_loki_logsとquery_loki_patternsは無効になりますが、query_loki_statsとanalyze_loki_labelsはセレクタを送るだけでログの中身は返さないため登録されたままです。ログ内容そのものへのアクセスを完全に止めたいなら--disable-lokiでカテゴリごと無効化する必要があります。

負のマッチャーだけではラベル一覧が取れない: namespace!~"vault"のような除外だけのマッチャーは、Lokiが「正のマッチャーを含まない単独セレクタ」を受け付けないため、ラベル列挙系のツールをうまくスコープできません。--loki-label-enumeration-fallbackでreject(既定、列挙自体を拒否)かunfiltered(ラベルのメタデータだけ無制限に列挙を許可、ログ本文は出さない)を選びます。

広い検索が一度に重すぎる: 件数を欲張ると、返却が大きくなってコンテキストを圧迫します。issue #761で挙がった回避策は、狭い時間範囲、行フィルタより先にラベルで絞ること、query_loki_statsで事前に規模を見積もること、limitを10〜20件に抑えることの4つです。compact形式は、この種の相談を受けて加わった出力オプションです。

サーバー起動時の警告を読み飛ばす: --loki-enforced-matchersを設定していても、--disable-apiなどの併用フラグが足りないとサーバーはその旨を起動時にログへ警告として出します。この警告を見落とすと、制限をかけたつもりで実際には迂回経路が残ります。

VictoriaLogsで急に拒否されるようになる: --loki-enforced-matchersを有効にした状態でVictoriaLogsデータソースへ問い合わせると、Lokiと同じ設定のまま複数バックエンドを併用している環境では、VictoriaLogsだけ動かなくなったように見えます。Lokiのツールは通るので、設定の不具合と取り違えやすい点に注意が必要です。

まとめ

Lokiツールを使えば、LogQLの文法を都度思い出さなくても自然言語からログ検索・ラベル調査・ログ量の把握まで進められます。実務での要点は、コストの大きいクエリを--loki-guardrail-modeで制御することと、機微なログストリームを見せたくないなら--loki-enforced-matchersと関連フラグをセットで止めることの2つです。ダッシュボード操作を含めた全体のRBAC設計はmcp-grafanaの導入とRBAC設計、障害時の当番確認はGrafana OnCallをClaudeで操作する記事を合わせて確認してください。

この記事を共有:XはてブLinkedIn