Azure Container Apps のログ監視 (Log Analytics & Application Insights & Azure Monitor) - Python アプリの例

:::note warn

Application Insights の Python SDK は 本記事でご紹介している OpenCensus 版は2024年９月のリタイアが発表されており、[**OpenTelemetry 版**](https://learn.microsoft.com/ja-jp/azure/azure-monitor/app/opentelemetry-enable?tabs=python)への移行が推奨されています。

OpenTelemetry 版の使い方については、[**こちらの記事**](https://qiita.com/YoshiakiOi/items/c4de9b1ffc01ecf292f9)をご参照ください。
:::

# 本記事について

本記事では、Azure Container Apps でのログ監視のアーキテクチャや取りうる方法の選択肢を見ていきます。Container Apps のログと一言で言っても、コンテナーのログやシステムのログ、アプリケーションのログなどがあります。また、サービス側の登場人物としては、Azure Log Analytics, Azure Application Insights, Azure Monitor になります。それぞれ、どのレイヤー (Container Apps 環境、Container Apps, アプリケーションコード) で実装が必要になるか、を見ていきます。

# Azure Container Apps でのログ監視の全体像

Azure Container Apps でのアプリとログ収集サービスの概略をまとめると以下の図のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/722d4649-820b-bbb4-9c58-6ae2640c30c6.png)

まず、Container Apps 環境では作成時にひとつの Log Analytics ワークスペースを指定します。これにより、Container Apps 環境上の各 Container Apps のコンソールログとシステムログが集約されます。もしアプリケーションからコンソールにログが吐き出されるように設定される場合、そのまま Log Analytics ワークスペースでコンソールログとしてそのログが検索できるようになります。ただし、コンソールログの場合は、コンソールに吐き出されたすべてのログデータをそのまま取り込むことになります。

https://learn.microsoft.com/ja-jp/azure/container-apps/logging

一方で、Application Insights を利用する方法もあります。Application Insights では単なるログ収集に加え、分散トレーシングや可用性テスト、メトリックの解析なども行えます。もし、アプリケーションからのログ送信をより詳細にコントロールしたい場合や、Application Insights の別機能も併せて監視に利用したい場合は、Application Insights の利用がおすすめです。Container Apps で Application Insights を利用したい場合には、SDK を利用してコードにインストルメンテーションする必要があります。

https://learn.microsoft.com/ja-jp/azure/azure-monitor/app/app-insights-overview?tabs=net

また、もし Dapr を Container Apps で利用している場合は、Dapr の分散トレーシングのテレメトリーを Dapr から Application Insights に吐き出すことができます。これを利用すると、Dapr のサイドカーコンテナーからどこに通信されているかを、コードの修正なしで簡単にとらえることができます。

https://learn.microsoft.com/ja-jp/azure/container-apps/dapr-overview?tabs=bicep1%2Cyaml

# 実装手順

ここからは、実際にどう設定を行えば、どのようなログが収集できるかを見ていきます。3 パターン ( ① Container Apps から Log Analytics への転送、② Application Insights への SDK を使った転送、③ Dapr から Application Insights への転送）それぞれで確認していきます。

## 1. Container Apps からのコンソールログ・システムログの Log Analytics ワークスペースへの送信 (Container Apps 環境での設定)

2023年6月現在、Container Apps からコンソールログ・システムログの Log Analytics ワークスペースへの送信には、下記の２つのオプションがあります。

### Option 1. Log Analytics ワークスペースの設定

Azure ログ分析を選んだ場合には、Log Analytics ワークスペースを指定するだけです。これでワークスペースへログが送信されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/964d58bd-5708-bcd7-381a-0d82b46d1027.png)


### Option 2. (Preview) Azure Monitor の設定

Azure Monitor を選んだ場合は、詳細な設定は後から行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/5cf59657-9af2-acff-675d-a4cf24d93791.png)

Container Apps 環境の作成後、診断設定より Log Analytics ワークスペースを設定します。こちらの設定の場合は取得するログを選択できたり、複数のワークスペースへのログ送信ができたり、ストレージアカウントや Event Hubs といった別リソースへログが転送できたり、といったメリットがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/1c268187-e7fc-ba21-922d-5b4abb298a25.png)


### コンソールログとシステムログの確認

コンソールログは、Log Analytics の ContainerAppConsoleLogs テーブルに格納されます。例えば、下記のクエリは、コンソールログで直近一時間のものを取り出して、時間順に並べています。(project 句で、特定の列だけ表示しています。）

```:Kusto クエリ
ContainerAppConsoleLogs | where TimeGenerated > ago(1h) | sort by TimeGenerated desc
| project TimeGenerated, ContainerAppName, Stream, Log
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/6cfe3f31-b19b-f836-5637-aa694a2ec31f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/2826dd57-f539-689b-be67-ad30f1f7374c.png)

こちらはコンソールログなので、アプリケーションから吐き出されたログ以外のレコードも多く入っていることがわかります。アプリケーションからのログのみを取り出したい場合は、次の Application Insights を利用します。

一方、システムログは ContainerAppSystemLogs テーブルに入ってきます。こちらはコンテナーの起動や停止、リビジョンの更新、プローブなどのログを記録しています。

同じくクエリ例になります。

```:Kusto クエリ
ContainerAppSystemLogs | where TimeGenerated > ago(1h) | sort by TimeGenerated desc 
| project TimeGenerated, ContainerAppName, Type, Log, Reason, EventSource
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/0690c33f-f558-7462-4f3a-a114e7ef14c9.png)

## 2. Container Apps 上の各コンテナー化されたアプリから Application Insights へのログ送信

これは、Container Apps 上のアプリに限らず、SDK を使ってアプリケーションから Application Insights にログを送信する方法になります。本記事では、Python のアプリを例に、SDK 経由でのログ送信を見ていきます。

### SDK の設定とコーディング

基本的には、下記の公式ドキュメントの記載の通りに実装すれば、ログが Application Insights の trace テーブルに格納されます。

https://learn.microsoft.com/ja-jp/azure/azure-monitor/app/opencensus-python#telemetry-type-mappings

ざっくりだけ抽出すると、pip install で下記のモジュールをインストールし、logger を下記のようにセットすると簡単にテストができます。(接続文字列は実際には、別の方法を使って保存・取得してください。)

```bash: pip install 
pip install opencensus-ext-azure opencensus-ext-fastapi
```

```python: Python ファイル
import logging
from opencensus.ext.azure.log_exporter import AzureLogHandler
from opencensus.ext.fastapi.fastapi_middleware import FastAPIMiddleware

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logger.addHandler(AzureLogHandler(connection_string="<Application Insights の接続文字列>"))

logger.info("出力したい内容")
```

### Application Insights に格納されたログの確認

Application Insights 側では、traces テーブル (Log Analytics では AppTraces テーブル) に格納されています。

たとえば、直近1時間以内のログを抽出し、時間順に並べ替えるには、下記のようなクエリを実行します。

```:Kusto クエリ
traces | where timestamp > ago(1h) |  sort by timestamp desc
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/f995e2d0-7953-99d4-cea7-f24b5a9b03bb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/efc3ce1e-44d2-6527-a97c-701ea3cb6ea6.png)

### ＊補足 - ログファイルに書き出されたものを Log Analytics に送信したい場合

ログファイルがすでにあり、その内容ごと、Log Analytics に送信したいというニーズもあるかもしれません。その場合は、Log Analytics の Log Ingest API (Python SDK) を利用してください。詳細については、下記の記事をご参照ください。

https://qiita.com/YoshiakiOi/items/4f52d6c45686b1de7554

## 3. Dapr (on Container Apps 環境) から Application Insights へのテレメトリーの送信

2023年6月現在、Dapr から直接分散トレーシングのテレメトリーを Application Insights へ送るには、Container Apps 環境の作成時に、送り先の Application Insights を指定しておく必要があります。これだけ行っていれば、あとは Container Apps 環境上のアプリが Dapr を経由して通信を行うと、自動的にテレメトリーを収集し、Application Insights で分析ができるようになります。

### CLI コマンドによる Container Apps 環境作成とその設定

この設定を行うには、CLI コマンドにて Container Apps 環境を作成します。コマンドは以下になります。(その他のオプションは任意で追加してください。)

```bash
az containerapp env create \
  --name <環境名> \
  --resource-group <リソースグループ名> \
  --location <リージョン名> \
  --dapr-instrumentation-key <利用する Application Insights のインストルメンテーションキー>
```

この Container Apps 環境の上に、Container Apps を作ります。その際に、すべての Container Apps 上で、Dapr を有効化しておきます。現在は、Azure Portal 上で簡単に有効化ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/4aab1947-ae5b-263d-39a9-bf0ac5f3c72a.png)

Dapr が有効化されると、コンテナーアプリで Dapr のサイドカーコンテナーが動き始めます。レプリカやログストリームでも確認ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/b4f3a84e-68fd-760b-1029-010a00d9444c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/cd17c512-a3ff-0719-7328-f0249b7acea1.png)


Python のアプリケーションコード側では、Dapr を使うようにします。たとえば、request モジュールのメソッドの場合は、headers に Dapr の App ID を追加し、URL を Localhost に変更します。(Dapr のデフォルトのポートは3500ですが、変更も可能です。）

```python:Python ファイル
headers = {'dapr-app-id': '<呼び出し先のアプリの Dapr App ID>'}
response = requests.get(url="http://localhost:3500/<path>", headers=headers)
```

### Application Insights でのアプリケーションマップとログの確認

アプリ間の呼び出しが、Dapr 経由で正常に行われると、自動的に Application Insights のアプリケーションマップに通信状況が可視化されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/764973ad-24b1-c7dd-2ae3-4e309ac6b61d.png)

ログとしては、Application Insights の requests や dependencies のテーブルに格納されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/ec87e555-e3d4-65a7-2fc9-c0fc6f6b82c9.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276225/41bfe64f-914b-2751-9847-783211bbd857.png)


# 最後に

＊本稿は、個人の見解に基づいた内容であり、所属する会社の公式見解ではありません。また、いかなる保証を与えるものでもありません。正式な情報は、各製品の販売元にご確認ください。