Azure Container Apps Azure Monitor Log Analyticsと統合され、コンテナー アプリのログを監視および分析するのに役立ちます。 ログ監視用にこのソリューションを選択すると、Container Apps 環境には、環境内で実行されているすべてのコンテナー アプリのシステム ログ データとアプリケーション ログ データを格納するための共通の場所を提供する Log Analytics ワークスペースが含まれます。
Azure CLIを使用して、Azure ポータルまたはコマンド シェルを使用してLog Analyticsテーブルに対してクエリを実行することで、ログ エントリにアクセスできます。
Azure Container Appsには、監視とトラブルシューティングに役立つ 3 種類のログが用意されています。
- コンソール ログ: アプリケーションによってこれらのログが生成されます。
- システム ログ: Container Apps サービスによってこれらのログが生成されます。
- HTTP ログ: 診断設定を使用して HTTP ログが有効になっている場合、イングレス 層はこれらのログを出力します。
システム ログ
Container Apps サービスでは、コンテナー アプリ レベルでのシステム ログ メッセージが提供されます。 システム ログでは、次のメッセージが出力されます。
| ソース | タイプ | メッセージ |
|---|---|---|
| Dapr | 情報 | dapr コンポーネント <component-name> がスコープ <dapr-component-scope> で正常に作成されました |
| Dapr | 情報 | dapr コンポーネント <component-name> がスコープ <component-type> で正常に更新されました |
| Dapr | エラー | dapr コンポーネント <component-name> の作成中にエラーが発生しました |
| ボリューム マウント | 情報 | ボリューム <volume-name> がリビジョン <revision-scope> に対して正常にマウントされました |
| ボリューム マウント | エラー | ボリューム <volume-name> のマウント中にエラーが発生しました |
| ドメインバインディング | 情報 | ドメイン<ドメイン>をコンテナー アプリ<コンテナー アプリ名>に正常に結び付けられました。 |
| 認証 | 情報 | アプリで認証が有効になっています。 認証構成を作成しています |
| 認証 | 情報 | 認証構成が正常に作成されました |
| トラフィックの重み | 情報 | リビジョン <revision-name\> のトラフィックの重み付けを <percentage>% に設定しています |
| リビジョンのプロビジョニング | 情報 | 新しいリビジョンを作成しています: <revision-name> |
| リビジョンのプロビジョニング | 情報 | リビジョン <name> が正常にプロビジョニングされました |
| リビジョンのプロビジョニング | 情報 | 'ActiveRevisionsMode=Single' 以降の古いリビジョンを非アクティブ化する |
| リビジョンのプロビジョニング | エラー | リビジョン <revision-name> のプロビジョニング中にエラーが発生しました。 ErrorCode: <[ErrImagePull]|[タイムアウト]|[コンテナーがクラッシュしています]> |
ContainerAppSystemLogs_CL テーブルに対してクエリを実行すると、システム ログ データにアクセスできます。 テーブルで最もよく使用される Container Apps 固有の列は次のとおりです。
| 列 | 説明 |
|---|---|
ContainerAppName_s |
コンテナー アプリ名 |
EnvironmentName_s |
Container Apps 環境名 |
Log_s |
ログメッセージ |
RevisionName_s |
リビジョン名 |
コンソール ログ
コンソール ログは、コンテナー アプリ内のコンテナーと Dapr サイドカーからの stderr メッセージおよび stdout メッセージに由来します。 コンソール ログは、ContainerAppConsoleLogs_CL テーブルを照会することで表示できます。
ヒント
適切に定義されたログ メッセージを使用してコードをインストルメント化すると、コードの実行方法を理解し、問題をデバッグするのに役立ちます。 ベスト プラクティスの詳細については、「 運用の設計」を参照してください。
ContainerAppConsoleLogs_CLで最もよく使用される Container Apps 固有の列は次のとおりです。
| 列 | 説明 |
|---|---|
ContainerAppName_s |
コンテナー アプリ名 |
ContainerGroupName_g |
レプリカ名 |
ContainerId_s |
コンテナー識別子 |
ContainerImage_s |
コンテナー イメージ名 |
EnvironmentName_s |
Container Apps 環境名 |
Log_s |
ログメッセージ |
RevisionName_s |
リビジョン名 |
HTTP ログ
Azure Container Appsは、Container Apps マネージド環境でAzure Monitor診断設定を使用して HTTP ログを出力できます。
API と Web トラフィックの動作を診断するときに、HTTP ログを使用して要求の量、パス、メソッド、応答の結果を調べます。
ContainerAppHTTPLogs スキーマには、次のフィールドと説明が含まれています。
| フィールド | タイプ | 説明 |
|---|---|---|
| 依頼 | ||
Method |
文字列 | HTTP 要求メソッド (たとえば、 GET、 POST)。 |
Path |
文字列 | クエリ文字列を含む要求パス。 トークンや API キーなどの機密性の高い値は、クライアントがクエリで渡す場合にここに表示される可能性があるため、それに応じて処理します。 |
Authority |
文字列 | クライアントによって送信される HTTP Host ヘッダー (または HTTP/2 :authority 擬似ヘッダー)。 |
Protocol |
文字列 | イングレスによって観測されたプロトコル バージョン。HTTP/1.1、HTTP/2、または HTTP/3 のいずれか。 |
UserAgent |
文字列 | クライアント User-Agent ヘッダー。 |
XForwardedFor |
文字列 |
X-Forwarded-For ヘッダーからのクライアント IP チェーン。 エンド ユーザー IP が含まれるため、PII として扱います。 |
BytesReceived |
long | クライアントから受信した要求本文のサイズ (バイト単位)(%BYTES_RECEIVED%)。 |
| 応答 | ||
StatusCode |
整数 (int) | クライアントに返される HTTP 応答状態コード。
0 は、応答が開始される前にクライアントが切断されたことを示します (%RESPONSE_CODE%)。 |
ResponseCodeDetails |
文字列 | 状態コードを設定するユーザーとその理由を説明する短いトークン。 たとえば、 via_upstream、 direct_response、 route_not_found、 upstream_per_try_timeout(完全なリスト) などです。 |
ResponseFlags |
文字列 | トランスポート レベルの条件を記述する 1 つ以上の短いコード。 たとえば、 - (なし)、 UH (正常なアップストリームなし)、 UT (アップストリーム タイムアウト)、 NR (ルートなし) (完全なリスト) などです。 |
BytesSent |
long | クライアントに送信される応答本文のサイズ (バイト単位)(%BYTES_SENT%)。 |
| Timing | ||
StartTime |
datetime | Time (UTC) イングレスが要求の処理を開始しました (%START_TIME%)。 |
RequestDuration |
long | 要求の開始から最後に送信された応答バイトまでの合計時間 (ミリ秒) (%DURATION%)。 |
| 識別子 | ||
RequestId |
文字列 | 要求の関連付け ID。 クライアントがヘッダーを指定した場合は x-request-id ヘッダーを反映し、それ以外の場合はイングレスによって値が生成されます。 UUID であるとは限りません。 |
ConnectionId |
文字列 | この要求が到着したダウンストリーム接続の識別子。 同じ接続に対する複数の要求で、この値 (%CONNECTION_ID%) が共有されます。 |
| アプリ/ルーティング | ||
ContainerAppName |
文字列 | 要求を処理したコンテナー アプリ。 |
RevisionName |
文字列 | 要求を処理したコンテナー アプリのリビジョン。 |
ReplicaName |
文字列 | 要求を処理したレプリカ (ポッド)。 |
EnvironmentName |
文字列 | アプリをホストしている Container Apps 環境。 |
| 上流 | ||
UpstreamHost |
文字列 | 要求 (IP:port) を処理したアップストリーム エンドポイントのアドレス (%UPSTREAM_HOST%)。 |
UpstreamRequestAttemptCount |
整数 (int) | 要求がアップストリームで試行された回数 (再試行を含む)。
0 は、試みられなかったという意味です。 |
| イングレス診断 | ||
EnvoyPodName |
文字列 | このレコードを生成したイングレス ポッドの名前。 インシデント調査中にイングレス ログを相互参照する場合に便利です。 |
EnvoyContainerId |
文字列 | イングレス インスタンスのコンテナー ID。 インシデント調査中にイングレス ログを相互参照する場合に便利です。 |
Note
HTTP ログを有効にすると、ContainerAppHTTPLogs テーブルがLog Analyticsに表示されるまでに数分かかることがあります。
Log Analyticsで HTTP ログにクエリを実行する
最初に次のトリアージに重点を置いたクエリを使用してから、次の追加の分析例を使用します。
最近の HTTP エラーを表示する
このクエリは、ダッシュボードに高いエラー率が表示された場合、顧客がエラーを報告する場合、または現在失敗しているものをすばやくトリアージする必要がある場合に使用します。
ContainerAppHTTPLogs
| where TimeGenerated > ago(1h)
| where StatusCode >= 400
| project TimeGenerated, ContainerAppName, RevisionName, Method, Path,
StatusCode, ResponseCodeDetails, RequestDuration, RequestId
| order by TimeGenerated desc
| take 100
ヒント
ResponseCodeDetailsチェックして、要求が失敗した理由を確認します。 たとえば、 route_not_found はルーティングの構成ミスを示しますが、 via_upstream はコンテナーがエラー自体を返したことを意味します。
遅いリクエストを見つける
このクエリは、アプリが遅いと感じる場合、待機時間の問題を調査している場合、またはパフォーマンスの修正を確認する場合に使用します。
ContainerAppHTTPLogs
| where TimeGenerated > ago(1h)
| where ContainerAppName == "<app-name>"
| top 50 by RequestDuration desc
| project TimeGenerated, Method, Path, StatusCode, RequestDuration,
ReplicaName, UpstreamRequestAttemptCount, RequestId
ヒント
RequestDuration はミリ秒単位で報告されます。
UpstreamRequestAttemptCount > 1と共に高い値が表示される場合は、要求が再試行され、合計時間が加算されます。
リビジョン別にリクエスト数とエラー率を追跡する
新しいリビジョンをデプロイして正常であることを確認する場合、または青/緑のロールアウトを実行していて、2 つのリビジョンを並べて比較する場合は、このクエリを使用します。
ContainerAppHTTPLogs
| where TimeGenerated > ago(6h)
| where ContainerAppName == "<app-name>"
| summarize Requests = count(),
Errors = countif(StatusCode >= 500),
ErrorRatePct = round(100.0 * countif(StatusCode >= 500) / count(), 2),
P95DurationMs = percentile(RequestDuration, 95)
by RevisionName, bin(TimeGenerated, 5m)
| order by TimeGenerated desc
| render timechart
ヒント
新しいリビジョンが突然 0 リクエストを処理し始めた場合、通常はイングレス構成でのトラフィックの重み付けに問題があることを意味します。 前のリビジョンよりもエラー率が高い新しいリビジョンまたは P95 はデプロイ回帰です。ロールバックを検討してください。
1 つの要求をエンドツーエンドでトレースする
このクエリは、顧客が特定の失敗したトランザクションを報告し、要求 ID (表示された x-request-id ヘッダー値) を提供する場合に使用します。 その正確な要求と関連するアプリ ログを見つける必要があります。
let _requestId = "<request-id>";
ContainerAppHTTPLogs
| where TimeGenerated > ago(24h)
| where RequestId == _requestId
| project TimeGenerated, ContainerAppName, RevisionName, ReplicaName,
Method, Path, StatusCode, ResponseCodeDetails, ResponseFlags,
RequestDuration, UpstreamHost, UserAgent, XForwardedFor
ヒント
上記の行の ReplicaName を取得したら、 ContainerAppConsoleLogs_CL を同じレプリカにフィルター処理し、 TimeGenerated 周りの小さな時間枠で結合し、その要求に対するアプリ独自のログ行を表示します。
失敗した上位のエンドポイントを特定する
多くのエラーが表示され、最初にフォーカスする場所がわからない場合は、このクエリを使用します。 このクエリでは、ほとんどのエラーの原因となるパスが表示されるため、影響によって修正に優先順位を付けることができます。
ContainerAppHTTPLogs
| where TimeGenerated > ago(24h)
| where StatusCode >= 400
| summarize Errors = count(),
DistinctClientIPs = dcount(XForwardedFor),
SampleStatusCodes = make_set(StatusCode, 5),
ExampleDetails = take_any(ResponseCodeDetails)
by ContainerAppName, Method, Path
| order by Errors desc
| take 20
ヒント
エラーと共に DistinctClientIPs 数が多い場合は、大きく影響する実際の問題が示されています。 通常、低カウントは、1 つの不適切な動作をするクライアント (スキャナーやバグのある再試行ループなど) を示します。
最近の HTTP ログ レコードを検査する
このクエリを使用して、最近の HTTP ログ レコードを調べます。
ContainerAppHTTPLogs
| where TimeGenerated > ago(2h)
| project TimeGenerated, Method, Path, StatusCode, ContainerAppName, EnvironmentName
| order by TimeGenerated desc
| take 100
一般的な HTTP ログ分析シナリオでは、次の例を使用します。
状態コードの配布
ContainerAppHTTPLogs
| where TimeGenerated > ago(24h)
| summarize Count = count() by toint(StatusCode)
| order by Count desc
エラーに重点を置いたビュー (4xx/5xx)
ContainerAppHTTPLogs
| where TimeGenerated > ago(2h)
| extend StatusCodeInt = toint(StatusCode)
| where StatusCodeInt >= 400
| project
Time=TimeGenerated,
StatusCode=StatusCodeInt,
Method,
Path,
Details=ResponseCodeDetails,
EnvName=EnvironmentName,
AppName=ContainerAppName,
Revision=RevisionName
| top 100 by Time desc
アプリとパスごとの待機時間 (P50/P95/P99)
ContainerAppHTTPLogs
| where TimeGenerated > ago(2h)
| summarize
Requests = count(),
P50 = percentile(RequestDuration, 50),
P95 = percentile(RequestDuration, 95),
P99 = percentile(RequestDuration, 99)
by ContainerAppName, Path
| order by P95 desc
Log Analytics を使用してログのクエリを実行する
Log Analytics は、ログ データの表示と分析に使用できる Azure portal のツールです。 Log Analyticsを使用すると、Kusto クエリを記述し、結果をグラフで並べ替え、フィルター処理、視覚化して傾向を特定し、問題を特定できます。 クエリ結果を対話的に操作したり、アラート、ダッシュボード、ブックなどの他の機能と一緒に使用したりできます。
Azure portal
コンテナー アプリ ページのサイドバー メニューの [ログ] から Log Analytics を起動します。 Monitor > Logs からLog Analyticsを開始することもできます。
Tables タブの Custom logs カテゴリに一覧表示されているテーブルを使用して、ログをクエリします。このカテゴリのテーブルは ContainerAppSystemLogs_CL と ContainerAppConsoleLogs_CL です。
次の Kusto クエリでは、 album-api という名前のコンテナー アプリのコンソール ログ エントリが表示されます。
ContainerAppConsoleLogs_CL
| where ContainerAppName_s == 'album-api'
| project Time=TimeGenerated, AppName=ContainerAppName_s, Revision=RevisionName_s, Container=ContainerName_s, Message=Log_s
| take 100
次の Kusto クエリでは、 album-api という名前のコンテナー アプリのシステム ログ エントリが表示されます。
ContainerAppSystemLogs_CL
| where ContainerAppName_s == 'album-api'
| project Time=TimeGenerated, EnvName=EnvironmentName_s, AppName=ContainerAppName_s, Revision=RevisionName_s, Message=Log_s
| take 100
Log Analyticsクエリとログ クエリの詳細については、Log Analytics チュートリアルを参照してください。
Azure CLI または PowerShell
Azure CLI を使用して、Container Apps ログに対してクエリを実行できます。
これらの Azure CLI クエリの例では、コンテナー アプリ名 "album-api" のログ レコードを格納しているテーブルを出力します。
project演算子の後のパラメーターは、テーブルの列を指定します。
$WORKSPACE_CUSTOMER_ID 変数には、Log Analytics ワークスペースの GUID があります。
次の例では、ContainerAppConsoleLogs_CL テーブルを照会します。
az monitor log-analytics query --workspace $WORKSPACE_CUSTOMER_ID --analytics-query "ContainerAppConsoleLogs_CL | where ContainerAppName_s == 'album-api' | project Time=TimeGenerated, AppName=ContainerAppName_s, Revision=RevisionName_s, Container=ContainerName_s, Message=Log_s, LogLevel_s | take 5" --out table
次の例では、ContainerAppSystemLogs_CL テーブルを照会します。
az monitor log-analytics query --workspace $WORKSPACE_CUSTOMER_ID --analytics-query "ContainerAppSystemLogs_CL | where ContainerAppName_s == 'album-api' | project Time=TimeGenerated, AppName=ContainerAppName_s, Revision=RevisionName_s, Message=Log_s, LogLevel_s | take 5" --out table