ども!最近バグ調査のたびに Azure CLI を叩いている龍ちゃんです。
バグ調査でコードを読むところ、AI にやらせると爆速なんですよね。処理の順序を追って、どこで何が呼ばれているかを整理するくらいなら、もう完全に任せてます。ここはめちゃくちゃ助かってます。
で、あるとき思ったんです。次はバグの原因まで見つけられるように、アプリのログも自由に見れる形にしたら、調査もっとはかどるんじゃね?と。
ただ、正直に言うと僕、KQL そんなに書けないんですよ。Application Insights のログを引くやつですね。書けないから今までポータルのグラフを眺めて終わっていました。
で、そこを整備してみたら、書けるようにならないまま読めるようになったんです。整備といっても大したことはしていなくて、Azure CLI を Claude Code に叩かせる形にしただけです。これがめちゃくちゃ良かったので共有します。
今回の内容です。
- 仮説を渡すと、それを確かめる集計がそのまま返ってくるという話
- 実際にどう頼んで、どう叩かせているか
- AI に Azure を触らせる前に、こっちで決めておいたこと
- それでも仮説は人間が立てたほうがいい、という話
なお、Application Insights そのものの説明はしません。社内の先輩の武井さんが書いた世界一わかりみの深いAPM 〜Application Insights〜という決定版があるので、そちらに譲ります。計装の入れ方も扱いません。すでに入っていて、必要な情報が出ている状態からのスタートです。KQL の書き方も解説しません。書けないので、動いたものをそのまま貼っていきます。
あともう1つ。Azure 側にも自然言語で聞ける仕組みが乗っています(Observability Agent)。ただ Azure Copilot へのアクセスが要って、今のところ英語のみなんですよね(2026年8月時点)。この記事はそっちの話ではないです。 手元の Claude Code から Azure CLI を叩く形の話をします。
うれしいのは、仮説をそのまま確かめられることでした
先に一番おいしいところを言います。
思いついた仮説を、そのまま確かめられるようになったんですよね。
バグを追っていると「たぶんこうなってるんじゃないか」が浮かぶじゃないですか。最初の1回だけ遅いんじゃないか、とか。特定のエンドポイントだけ詰まってるんじゃないか、とか。
前はそこで止まってました。確かめるには KQL を書かないといけなくて、書けないから調べながら組み立てて、たいてい1本目で力尽きる。だからポータルのグラフを眺めて「なんとなくそれっぽい」で終わっていたんです。
今は、その仮説を言葉のまま渡せば、確かめる集計が返ってきます。表を見て当たりか外れかが分かって、外れていたら次の仮説を投げる。この回転が速いことが、僕にとっての「ログが調査に使える」でした。

グラフを眺めるのと決定的に違うのはここだと思っていて、ポータルって「用意された切り口」を見る場所なんですよね。自分の仮説に合わせた切り口は自分で作るしかない。そこを肩代わりしてもらえると、仮説を出すコストだけ払えばよくなります。
生ログを丸ごと渡してるわけではないです
「AI にログを読ませる」と言うと、生ログをどさっと投げるイメージがあると思います。僕も最初はそう思っていました。
でも実際は逆で、KQL 側で集計してから返させています。AI が受け取るのは集計済みの表だけです。生ログが要る場面なら読ませますけど、基本は表です。
これ、トークンをケチるためだと思われがちなんですが、そこはあんまり関係なかったですね。効いたのは、集計の条件がクエリに残ることのほうでした。
生ログを渡して集計させると、その集計をどうやったのかが会話の中に消えます。後から「この数字どうやって出した?」と聞き直すことになる。クエリで集計してあれば、そのクエリ自体が手順書なんですよね。数字を疑いたくなったら、同じものをもう一度叩けばいい。
あと単純に、数を数えるところを AI にやらせるのが怖いんですよね。なので集計が要る作業は全部 KQL 側に寄せています。
ログで見えたことを、そのまま設定と突き合わせられます
これは後から効いてきたやつです。
ログを引くのが az monitor app-insights query で、リソースの設定は az functionapp show。同じ CLI なんですよね。
az functionapp show -g <リソースグループ> -n <関数アプリ名> \
--query "properties.functionAppConfig.scaleAndConcurrency" -o json
{ "alwaysReady": [ { "instanceCount": 1, "name": "http" } ],
"instanceMemoryMB": 2048,
"maximumInstanceCount": 40,
"triggers": {} }
この出力は Flex Consumption プランのものなので、別のプランだと形が変わります。
「ログ上はこう見えるけど、設定はこうなってる」の突き合わせがそのままつながります。ポータルだと画面を行き来してスクショを渡すことになって、渡した時点でどれがどこの値なのか分からなくなるんですよね。
実際は、知りたいことと仮説を渡してるだけです
じゃあ何を渡しているのか、という話です。
先に1つだけ言っておくと、az は権限が付いていればリソースを消せます。この後の「決めておいたこと」に注意書きを書いたので、手を動かす前にそこだけ読んでもらえると安心です。
渡しているのは2つだけです。知りたいことと、仮説。
こんな感じで言ってます。
この時間帯で遅かったやつをエンドポイント別に見たい。たぶん最初の1回だけ遅いんだと思う
これで返ってくるのがこういうクエリです。
requests
| where timestamp between (datetime(2026-07-20T00:00:00Z) .. datetime(2026-08-04T08:00:00Z))
| where cloud_RoleName == "<関数アプリ名>"
| extend path = tostring(parse_url(url).Path)
| where path endswith "/auth/csrf" or path endswith "/auth/login"
| summarize reqs=count(),
slowPct=round(100.0*countif(duration>5000)/count(),1),
p50=round(percentile(duration,50),0),
p90=round(percentile(duration,90),0)
by name, resultCode
ここで一回止まって、僕がクエリに目を通します。読み取りだけになっているか、対象がちゃんと絞れているか。この確認だけは毎回やっていて、問題なければ叩かせます。KQL が分からなくても、なんとなくは読めますよね(英語力さえあれば…)。引っかかったところは AI に聞けば済みます。
叩くのはこれです。
az monitor app-insights query --app <appId> \
--analytics-query "$(cat q.kql)" \
--start-time 2026-07-20T00:00:00Z --end-time 2026-08-04T08:00:00Z \
--query "tables[0].rows" -o tsv
エンドポイントごとに件数と p50 / p90 が並んだ表が返ってくるので、それを見て仮説が当たっていたかを判断します。外れてたら「じゃあインスタンス別でも見たい」と言えばすぐ次が出てきます。
細かいところを補足しておきますね。
クエリはヒアドキュメントでファイルに落としてから食わせています。シェルに直書きするとパイプと引用符だらけで事故るんですよね。ファイルにしておくと、クエリだけ差し替えて何回も回せます。何を叩いたのか?という痕跡をファイルで残すということですね。
<appId> は Application Insights のアプリケーション ID です。ポータルの Application Insights リソースから「API アクセス」を開くと載っています。
-o tsv にしているのは、そのまま次の集計に食わせたいからです。JSON のままだと、AI が読むにも人が見るにも一手増えます。
--start-time と --end-time は KQL 側の between と同じ範囲にしておくのがおすすめです。ずらすと、どっちの条件で絞られた結果を見ているのか分からなくなります。
ちなみに az monitor app-insights query は application-insights 拡張のコマンドなんですが、入っていなければ初回に勝手に入ります。ここは気にしなくて大丈夫でした。
あと、複雑なクエリだと CLI 側が弾いてくることがあります。そのときは「直して」と言えばそのまま通る形にしてくれるので、楽々です。ただ、内容は読んでおいて勉強につなげています。
AI に Azure を触らせる前に、決めておいたこと
ここからは運用の話です。
先に言っておくと、Azure 側の権限をどう設計するかは書きません。RBAC をどう振るかは組織ごとの運用の話で、僕が「こうしろ」と言えるものじゃないので。
ここで書くのは、AI に触らせる前にこっち側で決めておいたことです。3つあります。
認証方式は1つに決めておく
僕は az login で自分がログインして、その資格で AI に叩かせています。
理由は、とりあえず一番手軽だからです。常設のトークンをどこにも置かなくて済むのもいいところですね。
ただこれ、権限の縛りやすさと安全マージンを上げたくなったら、選択肢は増えていきます。サービスプリンシパルとか、マネージド ID とかですね。
このへんも武井さんが書いてくれているので、そちらに譲ります。もう多分怖くないサービスプリンシパルと世界一わかりみの深いマネージドID 〜ソースコードから資格情報を追い出そう!!〜です。僕は今回どちらも使っていないので、名前を挙げるだけにしておきます。
どれを選ぶかは次の注意書きにつながる話なので、そこでもう一度触れます。
どれを選ぶにしても、先に1つに決めておくことが大事だと思っていて。その場の思いつきで方式が混ざると、何の権限で何を叩いたのかが後から追えなくなります。
見せる対象を固定する
--app で読みにいく Application Insights を1つに固定して、where cloud_RoleName == "..." で対象のアプリまで絞っています。上に貼ったコマンドにもう入っているやつですね。
これ、安全の話であると同時に、精度の話でもあります。
安全のほうは単純で、対象を固定しておけば、AI が見にいける範囲がそのアプリのログの外に出ません。関係ない別チームのアプリのログまで読める状態にしておかない、という話ですね。
で、精度のほうがちょっと厄介でした。1つの Application Insights に複数のアプリが相乗りしていることがありますよね。僕の環境がまさにそれで、調べたい対象の API よりも、まったく関係のない別のアプリのほうがリクエスト件数が多かったです。あと、別のアプリの数字を自分のだと思って読むのが一番まずいですからね。
知らずに数を数えると全部混ざった値が出ますし、見た目は普通の数字なので間違いに気づけません。なので最初の1本は、これを流しておくのがおすすめです。
requests
| where timestamp between (datetime(...) .. datetime(...))
| summarize reqs=count(), instances=dcount(cloud_RoleInstance)
by cloud_RoleName
| order by reqs desc
cloud_RoleName ごとの内訳を出すだけのクエリです。1回叩いておけば、以降のクエリにフィルタを入れ忘れなくなります。僕は後から気づいたクチなので、ここだけは先にやっておいてほしいです。
読み取りだけにする
叩かせるのは読み取り系のコマンドだけにしています。
調査でやりたいのは現状を知ることなんで、書き込みが要る場面ってそもそも無いんですよね。無いなら最初から候補に入れない。
で、どうやって守らせているかというと、正直に言うと仕組みでは塞いでいません。クエリを先に作らせて、実行前に自分で目を通す。さっき書いたやつですね。あとは Claude Code に読ませる指示ファイル(CLAUDE.md)に方針を書いているくらいです。
なのでこれ、「AI が絶対に書き込めない」状態ではないです。人が見ているから成立している、くらいのものだと思ってください。ツール側の許可設定で塞ぐ手もあって、そっちのほうが確実だとは思っています。ここはまだ模索中で、運用フローに載せて正式に導入するところまでは行けていないですね。
注意:権限次第では、リソースを吹き飛ばせます
ここは強めに書いておきます。
az は調べるためだけのコマンドじゃないです。権限が付いていれば、リソースを消すこともできます。 つまり、AI に渡した資格に何が付いているかで、事故ったときの被害範囲が決まります。
上に書いた「読み取りだけにする」は、あくまでこっち側の運用でそうしているだけで、権限そのものを塞いでいるわけではありません。ここが効くのは権限側です。

なので、始める前に社内の Azure 運用の担当に確認してください。 どこまでの権限で触っていいのか、そもそも AI に叩かせていいのか。ここは環境ごとに答えが違うので、僕が書けるのは「確認しよう」までです。
さっきの認証方式の話に戻ると、縛りやすさと安全マージンを上げたければ選択肢は増えます。僕が az login にしているのは手軽さを取った結果であって、ここが正解というわけではないです。
じゃあ人間は要らないのか、というと逆でした
最後に、一番言いたかったことを書きます。
そもそも最初の KQL は、レビュアーの方が Issue のコメントで投げてくれたものでした。確認項目を並べたうえで、クエリの例まで付けてくれていたんです。
ただ、後から考えると、効いたのはクエリそのものじゃなかったんですよね。クエリは仮説さえ渡せば AI が書いてくれるので、あれが無くても回ったと思います。ありがたかったのは、その前に並んでいた「何を確認すべきか」のほうでした。
しかもその方は、コメントの最後にノイズの注意まで書いてくれていました。サンプリングで最初の要求が欠落することがある、といったやつです。App Insights は量が多いとログを間引くことがあるので、そうなると数え上げた件数がそのまま実数ではなくなるんですね。
この件、僕は最後まで確認していません。全数ある前提で率を出しました。ここは反省点です。
思ったんですけど。良い仮説を出せるかどうかって、そのシステムをどれだけ知っているかで決まるんですよね。
どんなログを吐いているのか。どういう構成で動いているのか。どこが詰まりやすいのか。それを知っている人間のほうが、確かめる価値のある問いを立てられます。AI はその問いを確かめるのがめちゃくちゃ速いだけで、問いそのものを出してくるわけじゃない。
だから「AI に読ませる形にしたら人間が要らなくなる」ではないです。むしろ逆で、仮説を出すところに人間が集中できるようになった、が正しい。KQL を書く時間が消えた分、何を疑うかを考える時間が増えた感じですね。
書いていないことが3つあります。実際どんなシナリオで何が見つかるのか、どんなログを吐いて customEvents に何を積むべきかは、APM をどう設計するかの世界なのでまた別で。読ませた数字をどう疑うかも、それだけで一本になるので入れていません。GitHub 側でも同じことをやっていますが、認証まわりの事情が違うので今回は Azure だけで区切りました。
まとめ
KQL を書けるようにならないまま、Application Insights の仮説検証を AI に任せた話でした。
- 渡すのは知りたいことと仮説の2つ。KQL に落とすのは AI の仕事です
- うれしいのは仮説をそのまま確かめられること。当たり外れが表で返ってきて、次の仮説に進めます
- 生ログではなく集計した表を返させます。クエリが手順書として残るのが効きます
- AI に触らせる前に、認証方式・見せる対象・読み取り限定の3つを決めておきます
- 権限次第ではリソースを消せます。始める前に社内の Azure 運用に確認してください
- 仮説を出すのは人間の仕事のままです。むしろそこに集中できるようになります
最初の一歩は、cloud_RoleName ごとの内訳を出すクエリ1本です。相乗りに気づかないまま数えると、以降の数字が全部ずれるので。
KQL が書けないから諦めていたログ、けっこうあると思うんですよね。書けるようになるより、叩かせる形を作るほうが早い気がします。
もし間違いを見つけたら、SNS でもメールでも問い合わせください。
ほなまた〜


