GenAIContent/AppGenAIContent移行後にプロンプトログが見つからない時のKQL修正方法

Azure Monitor Application InsightsやMicrosoft Foundryの監視で、これまで取得できていた生成AIのプロンプトや応答が突然KQLに返らなくなった場合、最初に確認すべきなのは障害ではなく参照テーブルの変更です。

今回の移行が原因であれば、プロンプトログが削除されたわけではありません。生成AIの入力、出力、システム指示、ツール呼び出しなどが、Application InsightsではgenAIContent、Log AnalyticsではAppGenAIContentという専用テーブルに格納されるようになっています。

そのため、dependenciestracescustomEventsや、AppDependenciesAppTracesAppEventsのプロパティを参照していたKQL、Workbook、アラートルールは修正が必要です。Microsoftは、Azure Monitor Application InsightsおよびMicrosoft Foundryを対象に、機密性の高い生成AIテレメトリを専用テーブルで保護する機能をパブリックプレビューとして案内しています。(Microsoft Azure)

目次

結論:プロンプトと応答は専用テーブルから取得する

クエリを実行する場所によって、使用するテーブル名が異なります。

クエリを実行する場所生成AIコンテンツのテーブル従来の主なテーブル
Application Insightsの「ログ」genAIContentdependenciestracescustomEvents
Log Analyticsワークスペースの「ログ」AppGenAIContentAppDependenciesAppTracesAppEvents

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は増えているのにWithPromptWithResponseが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として内容を確認する

InputMessagesOutputMessagesは文字列型です。ただし、実際には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の相関では、次の列を対応させます。

AppGenAIContentAppDependencies
TraceIdOperationId
SpanIdId

次の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

結合後にNameDurationMsが空になる場合は、次の確認用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ではなくAppTracesAppEventsに格納されることもあります。既存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を優先するため、同じTraceIdSpanIdが存在するときは専用テーブル側を採用します。従来クエリがAppTracesAppEventsを使用している場合は、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
トレースIDOperationIdTraceId
スパンIDIdSpanId

修正は次の順序で行います。

  1. Workbook内でgen_ai.input.messagesgen_ai.output.messagesを検索する
  2. クエリスコープがApplication InsightsかLog Analyticsか確認する
  3. 専用テーブルを起点とするKQLへ変更する
  4. グリッドやチャートの列バインドを変更する
  5. 時刻、エージェント名、モデル名、リソースIDのフィルターを再確認する
  6. 実データがある時間範囲で結果を比較する
  7. Workbookを閲覧する一般ユーザーの権限でも動作確認する

特に注意したいのが、Workbookのクエリスコープです。同じWorkbookでも、Application Insightsリソースを対象にすればgenAIContent、Log Analyticsワークスペースを対象にすればAppGenAIContentを使用します。

クエリだけをコピーしてスコープを変更すると、テーブル名の違いで動作しなくなることがあります。

アラートルールは内容監視と運用監視を分ける

すべてのアラートをAppGenAIContentへ移す必要はありません。

処理時間、失敗率、例外、HTTP結果コードなどのアラートは、引き続きAppDependenciesAppRequestsAppExceptionsなどの運用テレメトリを使用する方が適しています。

一方、次のような生成内容そのものを条件にしたアラートは、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

移行後は、次の二つを別々に設計すると管理しやすくなります。

アラートの目的推奨テーブル
モデル呼び出しの失敗、遅延、可用性AppDependenciesAppRequestsAppExceptions
プロンプト、応答、ツール引数の内容AppGenAIContent
エージェントやモデルごとの利用状況AppGenAIContentと運用テーブルを結合
ログ取得自体の停止検知AppGenAIContentの一定期間の件数

プロンプト本文を使ったアラートは、機密情報をアラート通知やインシデント管理システムへ転記してしまう可能性があります。アラート結果には本文を含めず、TraceIdSpanIdAgentNameなどの調査用識別子だけを出す設計が安全です。

AppGenAIContentが0件なら権限も確認する

AppGenAIContentが保護テーブルに設定されている場合、権限不足のユーザーがKQLを実行しても、明確なアクセス拒否エラーが表示されないことがあります。

Microsoftのドキュメントでは、保護テーブルに対する権限を持たないユーザーがクエリすると、クエリ自体は成功しても0行が返る動作が示されています。ログ欠損と非常に見分けにくいため注意が必要です。(Microsoft Learn)

次の順序で確認します。

  1. Log Analyticsワークスペースを開く
  2. 「テーブル」からAppGenAIContentを選択する
  3. 保護レベルがProtectedになっているか確認する
  4. 実行ユーザーに必要なロールがあるか確認する
  5. 権限を持つ管理者と一般ユーザーで同じ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または列バインドが古いテーブル名、列名、クエリスコープを更新する
移行期間に件数が二重になる従来テーブルと専用テーブルの二重格納TraceIdSpanIdで重複を排除する
アラートが発火しなくなった旧テーブルのプロパティを参照している内容監視部分だけAppGenAIContentへ変更する
古いログは見えるが新しいログだけ見えない変更は新規取り込みデータに適用される取得日時を分けて新旧テーブルを確認する

恒久対応として実施すること

今回の変更では、生成AIコンテンツと運用メタデータを分けて考える必要があります。

プロンプト、応答、システム指示、ツール引数はAppGenAIContentを参照します。一方、処理時間、成功状態、結果コード、例外などは、従来どおりAppDependenciesAppExceptionsを利用します。両方が必要な画面では、TraceIdSpanIdを使って結合します。

対応は次の順序で進めると安全です。

  1. AppGenAIContentに新しいデータがあるか確認する
  2. Application InsightsとLog Analyticsのクエリスコープを確認する
  3. 保護テーブルの権限を確認する
  4. 旧KQLのgen_ai.*参照を洗い出す
  5. Workbookとレポートを専用テーブルへ変更する
  6. 内容を条件にするアラートだけをAppGenAIContentへ移す
  7. 移行期間の二重集計を防止する
  8. 一般ユーザーとアラートの実行環境で再テストする
  9. 一時的なオプトアウトに依存せず、専用テーブルへ完全移行する

最初に行うべき作業は、障害調査やSDKの再導入ではありません。まずAppGenAIContentを直接検索し、データ、クエリスコープ、アクセス権の三点を切り分けてください。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次