Azure Monitor Application InsightsやMicrosoft Foundryの監視で、これまで取得できていた生成AIのプロンプトや応答が突然KQLに返らなくなった場合、最初に確認すべきなのは障害ではなく参照テーブルの変更です。
今回の移行が原因であれば、プロンプトログが削除されたわけではありません。生成AIの入力、出力、システム指示、ツール呼び出しなどが、Application InsightsではgenAIContent、Log AnalyticsではAppGenAIContentという専用テーブルに格納されるようになっています。
そのため、dependencies、traces、customEventsや、AppDependencies、AppTraces、AppEventsのプロパティを参照していたKQL、Workbook、アラートルールは修正が必要です。Microsoftは、Azure Monitor Application InsightsおよびMicrosoft Foundryを対象に、機密性の高い生成AIテレメトリを専用テーブルで保護する機能をパブリックプレビューとして案内しています。(Microsoft Azure)
結論:プロンプトと応答は専用テーブルから取得する
クエリを実行する場所によって、使用するテーブル名が異なります。
| クエリを実行する場所 | 生成AIコンテンツのテーブル | 従来の主なテーブル |
|---|---|---|
| Application Insightsの「ログ」 | genAIContent | dependencies、traces、customEvents |
| Log Analyticsワークスペースの「ログ」 | AppGenAIContent | AppDependencies、AppTraces、AppEvents |
Application InsightsとLog Analyticsでは、同じテレメトリでもテーブル名と列名が異なります。Log Analytics側では、プロンプトがInputMessages、応答がOutputMessages、トレースIDがTraceId、スパンIDがSpanIdとして格納されます。(Microsoft Learn)
まず、Log Analyticsで次のKQLを実行してください。
AppGenAIContent
| where TimeGenerated >= ago(24h)
| project
TimeGenerated,
TraceId,
SpanId,
AgentName,
ModelName,
InputMessages,
OutputMessages
| order by TimeGenerated desc
Application Insightsリソースの「ログ」から実行する場合は、次のように確認します。
genAIContent
| where timestamp >= ago(24h)
| order by timestamp desc
AppGenAIContentをApplication Insights側で実行したり、genAIContentをLog Analytics側で実行したりすると、テーブルを解決できないエラーになることがあります。ログがないと判断する前に、クエリスコープを確認してください。
なぜ従来のKQLでプロンプトが返らなくなったのか
従来は、OpenTelemetryの生成AI属性が、モデル呼び出しを表す依存関係やトレースのプロパティとして格納されていました。
代表的な属性は次のとおりです。
| OpenTelemetry属性 | 内容 | AppGenAIContentの列 |
|---|---|---|
gen_ai.input.messages | モデルに送信した入力や会話履歴 | InputMessages |
gen_ai.output.messages | モデルが返した応答 | OutputMessages |
gen_ai.system_instructions | システム指示 | SystemInstructions |
gen_ai.tool.definitions | 利用可能なツール定義 | ToolDefinitions |
gen_ai.tool.call.arguments | ツール呼び出しの引数 | ToolCallArguments |
gen_ai.tool.call.result | ツールの実行結果 | ToolCallResult |
gen_ai.evaluation.explanation | 評価処理が生成した説明 | EvaluationExplanation |
これらの値は、個人情報や機密情報を含む可能性があります。そのためMicrosoftは、通常のパフォーマンス監視用テレメトリから分離し、より厳格なアクセス制御を設定できる専用テーブルへ移しています。(Microsoft Learn)
Microsoftの公式ドキュメントでは、移行スケジュールが次のように示されています。
| 時期 | 格納動作 |
|---|---|
| 2026年9月30日より前 | 従来テーブルとAppGenAIContentの両方へ格納 |
| 2026年9月30日以降 | 新しく取り込まれる生成AIコンテンツの値は原則AppGenAIContentへ格納 |
| 2027年9月30日以降 | 一時的なオプトアウトの有無にかかわらず専用テーブルへ一本化 |
2026年9月30日以降も、従来テーブルから属性キーそのものが消えるとは限りません。ただし、実際のプロンプトや応答ではなく、AppGenAIContentを参照するための短いポインターが入るようになります。
また、protectGenAISensitiveDataプレビューフラグを登録しているサブスクリプションでは、2026年9月30日より前でも専用テーブルのみへ格納する動作を先行適用できます。そのため、移行日より前に従来のKQLが返らなくなった場合も、まずAppGenAIContentを確認する必要があります。(Microsoft Learn)
なお、Microsoft FoundryやApplication Insightsの組み込み監視画面は、この変更へ自動的に対応します。影響を受けやすいのは、利用者が独自に作成したKQL、Workbook、ダッシュボード、アラート、レポートです。
最初に実行する切り分け用KQL
AppGenAIContentにレコードが届いているか確認する
最初からプロンプト本文を検索するのではなく、時間単位の件数を確認します。
AppGenAIContent
| where TimeGenerated >= ago(24h)
| summarize
Records = count(),
WithPrompt = countif(isnotempty(InputMessages)),
WithResponse = countif(isnotempty(OutputMessages)),
WithToolCall = countif(
isnotempty(ToolCallArguments)
or isnotempty(ToolCallResult)
)
by bin(TimeGenerated, 1h)
| order by TimeGenerated asc
Recordsは増えているのにWithPromptやWithResponseが0の場合、すべてのスパンがプロンプトや応答を持つとは限らない点に注意してください。ツール呼び出し、エージェント制御、評価処理など、モデルの入出力を含まないレコードもあります。
利用可能な列を確認する
パブリックプレビュー中は、SDKや計装方式によって利用する列や属性構造が異なる可能性があります。実際のスキーマを確認するには、次のKQLを使用します。
AppGenAIContent
| getschema
Application Insights側では次のように実行します。
genAIContent
| getschema
KQLで存在しない列をprojectすると、レコードの有無に関係なくクエリが失敗します。既存のWorkbookを修正するときは、先にgetschemaで列名を確認すると安全です。
プロンプトと応答を一覧表示するKQL
Log Analyticsで生成AIの主要なコンテンツを確認する基本形は次のとおりです。
AppGenAIContent
| where TimeGenerated >= ago(24h)
| project
TimeGenerated,
TraceId,
SpanId,
AgentId,
AgentName,
ModelName,
InputMessages,
OutputMessages,
SystemInstructions,
ToolDefinitions,
ToolCallArguments,
ToolCallResult,
EvaluationExplanation,
ServiceName,
RoleName
| order by TimeGenerated desc
AppGenAIContentには、入力と出力だけでなく、エージェント名、モデル名、システム指示、ツール呼び出し、サービス名、トレース相関用IDなどが用意されています。(Microsoft Learn)
特定の文字列を含む会話を検索する
let keyword = "返品手続き";
AppGenAIContent
| where TimeGenerated >= ago(7d)
| where InputMessages contains keyword
or OutputMessages contains keyword
| project
TimeGenerated,
TraceId,
SpanId,
AgentName,
ModelName,
InputMessages,
OutputMessages
| order by TimeGenerated desc
本番環境で顧客名、メールアドレス、注文番号などを直接検索する場合は、検索権限やログ利用ルールを確認してください。プロンプトと応答は、通常のエラーコードや処理時間とは異なり、業務データそのものを含む可能性があります。
JSONとして内容を確認する
InputMessagesとOutputMessagesは文字列型です。ただし、実際にはJSON形式のメッセージ配列が格納されることがあります。
AppGenAIContent
| where TimeGenerated >= ago(24h)
| extend
InputJson = parse_json(InputMessages),
OutputJson = parse_json(OutputMessages)
| project
TimeGenerated,
TraceId,
SpanId,
ModelName,
InputJson,
OutputJson
| take 50
最初から次のような固定パスを決め打ちするのは避けてください。
InputJson[0].content
SDK、OpenTelemetryのセマンティック規約、モデルAPIの形式によって、メッセージの階層構造が異なる可能性があるためです。まず展開前のJSONを確認し、その後にmv-expandやプロパティ参照を追加します。
AppDependenciesの処理時間や成功状態と結合する
AppGenAIContentにはプロンプトや応答が格納されますが、従来のAppDependenciesには、モデル呼び出しの処理時間、成功状態、結果コードなどの運用メタデータが残ります。
一般的なW3C Trace ContextおよびOpenTelemetryの相関では、次の列を対応させます。
| AppGenAIContent | AppDependencies |
|---|---|
TraceId | OperationId |
SpanId | Id |
次のKQLは、プロンプトとモデル呼び出しの処理時間を結合する例です。
let ContentRows =
AppGenAIContent
| where TimeGenerated >= ago(24h)
| project
ContentTime = TimeGenerated,
TraceId,
SpanId,
AgentName,
ModelName,
InputMessages,
OutputMessages,
SystemInstructions,
ToolCallArguments,
ToolCallResult;
ContentRows
| join kind=leftouter (
AppDependencies
| where TimeGenerated >= ago(24h)
| project
SpanTime = TimeGenerated,
OperationId,
Id,
AppRoleName,
Name,
Target,
DependencyType,
DurationMs,
Success,
ResultCode
) on
$left.TraceId == $right.OperationId,
$left.SpanId == $right.Id
| project
ContentTime,
SpanTime,
TraceId,
SpanId,
AppRoleName,
Name,
Target,
DependencyType,
DurationMs,
Success,
ResultCode,
AgentName,
ModelName,
InputMessages,
OutputMessages
| order by ContentTime desc
結合後にNameやDurationMsが空になる場合は、次の確認用KQLでIDの形式を比較します。
AppGenAIContent
| where TimeGenerated >= ago(1h)
| project TraceId, SpanId
| take 10
AppDependencies
| where TimeGenerated >= ago(1h)
| project OperationId, Id, Name, DependencyType
| take 10
計装方式によっては、該当するメタデータがAppDependenciesではなくAppTracesやAppEventsに格納されることもあります。既存KQLがどのテーブルを起点としていたかを確認し、実際に一致する相関IDを使用してください。
移行前後のデータを同じKQLで扱う
専用テーブル導入前の古いデータと、移行後のデータを一つのWorkbookで扱いたい場合は、専用テーブルを優先しつつ、従来テーブルをフォールバックとして結合します。
次は、従来のプロンプトがAppDependencies.Propertiesに格納されていた場合の例です。
let startTime = ago(30d);
let DedicatedRows =
AppGenAIContent
| where TimeGenerated >= startTime
| project
TimeGenerated,
TraceId,
SpanId,
InputMessages,
OutputMessages,
SourceTable = "AppGenAIContent";
let LegacyRows =
AppDependencies
| where TimeGenerated >= startTime
| extend
InputMessages =
tostring(Properties["gen_ai.input.messages"]),
OutputMessages =
tostring(Properties["gen_ai.output.messages"])
| where isnotempty(InputMessages)
or isnotempty(OutputMessages)
| project
TimeGenerated,
TraceId = OperationId,
SpanId = Id,
InputMessages,
OutputMessages,
SourceTable = "AppDependencies";
union DedicatedRows, LegacyRows
| extend SourcePriority =
iff(SourceTable == "AppGenAIContent", 2, 1)
| summarize arg_max(SourcePriority, *) by TraceId, SpanId
| project-away SourcePriority
| order by TimeGenerated desc
専用テーブルと従来テーブルの両方に同じデータが格納される移行期間は、単純なunionだけでは二重集計になる可能性があります。
この例ではAppGenAIContentを優先するため、同じTraceIdとSpanIdが存在するときは専用テーブル側を採用します。従来クエリがAppTracesやAppEventsを使用している場合は、LegacyRows部分を現在のKQLに合わせて変更してください。
Workbookを修正するポイント
Workbookでは、KQLだけでなく、列名に依存した表示設定も修正する必要があります。
| 修正対象 | 従来の参照例 | 移行後 |
|---|---|---|
| プロンプト | Properties["gen_ai.input.messages"] | InputMessages |
| 応答 | Properties["gen_ai.output.messages"] | OutputMessages |
| システム指示 | Properties["gen_ai.system_instructions"] | SystemInstructions |
| ツール引数 | Properties["gen_ai.tool.call.arguments"] | ToolCallArguments |
| ツール結果 | Properties["gen_ai.tool.call.result"] | ToolCallResult |
| トレースID | OperationId | TraceId |
| スパンID | Id | SpanId |
修正は次の順序で行います。
- Workbook内で
gen_ai.input.messagesやgen_ai.output.messagesを検索する - クエリスコープがApplication InsightsかLog Analyticsか確認する
- 専用テーブルを起点とするKQLへ変更する
- グリッドやチャートの列バインドを変更する
- 時刻、エージェント名、モデル名、リソースIDのフィルターを再確認する
- 実データがある時間範囲で結果を比較する
- Workbookを閲覧する一般ユーザーの権限でも動作確認する
特に注意したいのが、Workbookのクエリスコープです。同じWorkbookでも、Application Insightsリソースを対象にすればgenAIContent、Log Analyticsワークスペースを対象にすればAppGenAIContentを使用します。
クエリだけをコピーしてスコープを変更すると、テーブル名の違いで動作しなくなることがあります。
アラートルールは内容監視と運用監視を分ける
すべてのアラートをAppGenAIContentへ移す必要はありません。
処理時間、失敗率、例外、HTTP結果コードなどのアラートは、引き続きAppDependencies、AppRequests、AppExceptionsなどの運用テレメトリを使用する方が適しています。
一方、次のような生成内容そのものを条件にしたアラートは、AppGenAIContentへ変更します。
let marker = "REDACTED_TEST_MARKER";
AppGenAIContent
| where TimeGenerated > ago(10m)
| where InputMessages contains marker
or OutputMessages contains marker
| summarize HitCount = count()
| where HitCount > 0
移行後は、次の二つを別々に設計すると管理しやすくなります。
| アラートの目的 | 推奨テーブル |
|---|---|
| モデル呼び出しの失敗、遅延、可用性 | AppDependencies、AppRequests、AppExceptions |
| プロンプト、応答、ツール引数の内容 | AppGenAIContent |
| エージェントやモデルごとの利用状況 | AppGenAIContentと運用テーブルを結合 |
| ログ取得自体の停止検知 | AppGenAIContentの一定期間の件数 |
プロンプト本文を使ったアラートは、機密情報をアラート通知やインシデント管理システムへ転記してしまう可能性があります。アラート結果には本文を含めず、TraceId、SpanId、AgentNameなどの調査用識別子だけを出す設計が安全です。
AppGenAIContentが0件なら権限も確認する
AppGenAIContentが保護テーブルに設定されている場合、権限不足のユーザーがKQLを実行しても、明確なアクセス拒否エラーが表示されないことがあります。
Microsoftのドキュメントでは、保護テーブルに対する権限を持たないユーザーがクエリすると、クエリ自体は成功しても0行が返る動作が示されています。ログ欠損と非常に見分けにくいため注意が必要です。(Microsoft Learn)
次の順序で確認します。
- Log Analyticsワークスペースを開く
- 「テーブル」から
AppGenAIContentを選択する - 保護レベルが
Protectedになっているか確認する - 実行ユーザーに必要なロールがあるか確認する
- 権限を持つ管理者と一般ユーザーで同じKQLを比較する
保護テーブル全体を参照する利用者には、Privileged Monitoring Data Readerロールを使用できます。特定テーブルだけに絞る場合は、ABAC条件を含むカスタムロールを検討します。
Microsoft Foundryのトレースを参照する場合も、通常はLog Analytics Readerが必要です。基盤となるテーブルが保護されている場合は、追加でPrivileged Monitoring Data Readerが必要と案内されています。(Microsoft Learn)
FoundryにはトレースがあるのにKQLでは見えない場合
Microsoft Foundryのトレース画面には実行履歴が表示されているのに、Log AnalyticsのKQLでは0件になる場合、次の可能性が高くなります。
| 状況 | 確認内容 |
|---|---|
Foundryでは表示されるがAppDependenciesでは本文が空 | 専用テーブルへの移行が原因 |
Foundryでは表示されるがAppGenAIContentが0件 | 保護テーブルの権限、クエリ対象ワークスペースを確認 |
| FoundryとApplication Insightsが別ワークスペースを参照 | Foundryプロジェクトの接続済みリソースを確認 |
| 古い時間範囲だけ検索している | Azure portalの時間範囲とKQLのwhere条件を確認 |
| 新しい実行だけ見えない | エージェントを再実行し、トレース取り込みを確認 |
| トレース自体がない | FoundryプロジェクトとApplication Insightsの接続を確認 |
Foundryのサーバー側トレースは、Application Insightsリソースをプロジェクトへ接続することで収集されます。まずFoundryで新しいエージェント実行を発生させ、トレース画面とAppGenAIContentを同じ時間範囲で比較してください。(Microsoft Learn)
プレビューフラグの状態を確認する
2026年9月30日より前に専用テーブルのみへ切り替わっている場合は、protectGenAISensitiveDataが登録されている可能性があります。
Azure CLIでは次のように確認できます。
az feature show \
--namespace Microsoft.Insights \
--name protectGenAISensitiveData \
--output table
一時的なオプトアウト状態も確認します。
az feature show \
--namespace Microsoft.Insights \
--name optOutProtectGenAISensitiveData \
--output table
専用テーブルへの移行を先行適用するコマンドは次のとおりです。
az feature register \
--namespace Microsoft.Insights \
--name protectGenAISensitiveData
移行期限後も従来の格納動作を一時的に維持する必要がある場合は、次のオプトアウトが用意されています。
az feature register \
--namespace Microsoft.Insights \
--name optOutProtectGenAISensitiveData
オプトアウトを終了する場合は、登録を解除します。
az feature unregister \
--namespace Microsoft.Insights \
--name optOutProtectGenAISensitiveData
optOutProtectGenAISensitiveDataは恒久的な対策ではなく、2027年9月30日に終了する予定です。Workbookやアラートの改修時間を確保するための一時的な回避策として扱い、最終的にはAppGenAIContentへ移行してください。
プレビュー機能の登録や解除にはMicrosoft.Features/*権限が必要で、組み込みのContributorまたはOwnerロールにはこの権限が含まれます。(Microsoft Learn)
よくある症状と修正方法
| 症状 | 主な原因 | 修正方法 |
|---|---|---|
AppDependenciesはあるがプロンプトが空 | 専用テーブルへの移行 | AppGenAIContentを参照する |
Failed to resolve tableが出る | クエリスコープとテーブル名が不一致 | Application InsightsではgenAIContent、Log AnalyticsではAppGenAIContentを使う |
AppGenAIContentが0件 | 時間範囲、接続先、権限の問題 | 時間範囲とFoundryの接続先を確認し、保護テーブル権限を検証する |
| 管理者は見えるが一般ユーザーは0件 | 保護テーブルのアクセス制御 | Privileged Monitoring Data Readerまたは適切なカスタムロールを付与する |
| Workbookだけ表示されない | KQLまたは列バインドが古い | テーブル名、列名、クエリスコープを更新する |
| 移行期間に件数が二重になる | 従来テーブルと専用テーブルの二重格納 | TraceIdとSpanIdで重複を排除する |
| アラートが発火しなくなった | 旧テーブルのプロパティを参照している | 内容監視部分だけAppGenAIContentへ変更する |
| 古いログは見えるが新しいログだけ見えない | 変更は新規取り込みデータに適用される | 取得日時を分けて新旧テーブルを確認する |
恒久対応として実施すること
今回の変更では、生成AIコンテンツと運用メタデータを分けて考える必要があります。
プロンプト、応答、システム指示、ツール引数はAppGenAIContentを参照します。一方、処理時間、成功状態、結果コード、例外などは、従来どおりAppDependenciesやAppExceptionsを利用します。両方が必要な画面では、TraceIdとSpanIdを使って結合します。
対応は次の順序で進めると安全です。
AppGenAIContentに新しいデータがあるか確認する- Application InsightsとLog Analyticsのクエリスコープを確認する
- 保護テーブルの権限を確認する
- 旧KQLの
gen_ai.*参照を洗い出す - Workbookとレポートを専用テーブルへ変更する
- 内容を条件にするアラートだけを
AppGenAIContentへ移す - 移行期間の二重集計を防止する
- 一般ユーザーとアラートの実行環境で再テストする
- 一時的なオプトアウトに依存せず、専用テーブルへ完全移行する
最初に行うべき作業は、障害調査やSDKの再導入ではありません。まずAppGenAIContentを直接検索し、データ、クエリスコープ、アクセス権の三点を切り分けてください。

コメント