JavaScript  と Node.js 用の Application Insights SDK で分散トレースを試してみる

# はじめに
この記事は、Microsoft Azure Tech Advent Calendar 2021 の 6 日目の記事です。
Azure VM や App Service などにデプロイされた Web アプリケーションを監視するための Application Insights に関する記事を書かせていただきます。


# Application Insights とは
Application Insights とは、Web アプリケーションを監視するためのサービスです。
Application Insights SDK やエージェントなどが監視対象となるテレメトリを Application Insights リソースへ転送し、転送されたテレメトリを Azure Monitor によって監視 ・ 分析が可能です。
それにより、システム全体に悪影響を及ぼす前に事前に対処が出来たり、パフォーマンス低下に対するボトルネック調査などが簡単に行えることが出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192129/3e4afb8b-04aa-2244-f819-12a6e48b7817.png)

まぁようするに、リクエストに対するレスポンス時間や、アプリケーションが出力しているログ データ ・ 発生した例外情報などを、少ない労力で Application Insights のワークスペースへ転送することができ、KQL というクエリ言語を使って簡単に分析が行える便利なサービスです!

いろんな機能があります。
詳細は下記の公開情報を見ていただければと思います!

- [Application Insights とは何か?](https://docs.microsoft.com/ja-jp/azure/azure-monitor/app/app-insights-overview)


# 本記事の目的
Frontend 向けの JavaScript 用 Application Insights SDK と、Backend 向けの Application Insights SDK を使った、分散トレースについて記事を書きたいと思います。

とある SPA があったとして、クライアントがその SPA にアクセスしたとします。
その場合、Frontend で JavaScript の処理が走り、Backend からデータを取得するために REST API を呼び出す。
呼び出された Backend は、データベースや別のシステムにアクセスしてなんらかのデータを取得し、Frontend へ返却する。
Frontend は、Backend から取得したデータを使ってレンダリング。
こういうシナリオってよくあると思います。

Application Insights をご利用いただけば、Frontend や Backend、別の Web アプリケーションなどのテレメトリを収集することが可能です。
それにより、それぞれのサービスのログ データやパフォーマンス データを分析することが可能で、パフォーマンス低下の原因や異常発生時の調査などが実施可能となります。

Application Insights では、それぞれのサービスから出力されたテレメトリを関連付けることが可能です。
その結果、クライアントからのアクセスに対して、Frontend ・ Backend で出力されたログ データを、一気通貫で取得し分析することが可能となります。
テレメトリを関連付けるために、分散トレースという機能を有効化する必要があります。
今回はその分散トレースについて記事を書きたいと思います。

- [分散トレースとは](https://docs.microsoft.com/ja-jp/azure/azure-monitor/app/distributed-tracing)


# 前提条件
## 環境
私が実際に検証した環境は下図のとおりです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192129/e5cdbe57-c769-889b-77b5-1e25c6c8df67.png)

- Frontend は、React で作成された Web アプリケーション。Application Insights SDK (JavaScript) が組み込まれている。
- Backend は、REST API と GraphQL が実装された Web サーバー。Application Insights SDK (Node.js) が組み込まれている。
- User は、Frontend の React ベース Web アプリケーションにアクセス。
- Frontend は Backend と通信する。それは、Backend に実装された REST API と GraphQL を呼び出すため。
- Frontend と Backend は、同一の Application Insights リソースを用いて監視される。


## Web アプリケーションについて
すごく残念なデザインで恐縮です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192129/3448eba0-12c8-3d4d-8e21-7c9457ae5165.png)

この Web アプリケーション を使えば、Backend に実装された REST API と GraphQL を呼び出すことが出来ます。
その結果、Frontend から Application Insights リソース に対して Dependencies のログを送信することを期待します。
また、Backend からも Application Insights リソースに対して、Requests のログが送信されることも期待します。

※ Dependencies のログ : 当該アプリケーションから DB や 他システムにアクセスした際に Application Insights に記録されるテレメトリの一種です。
※ Requests のログ : クライアントから受け取ったリクエストに対してレスポンスを返した際に、Application Insights に記録されるテレメトリの一種です。
※ Application Insights によって収集されるテレメトリに関しては、[こちら](https://docs.microsoft.com/ja-jp/azure/azure-monitor/app/data-model)をご確認ください。

# 説明
Web アプリケーションにアクセスして、REST API や GraphQL を実行すると、当該 Application Insights リソースに下図のような分散トレースが記録されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192129/9d266299-453b-ce0b-44cf-96a0bcb3b9f0.png)

```
(requests | union dependencies | union pageViews)
| where operation_Id == "78f9a8952aaf4d03b5c9ce1e0cd24fc5"
| project timestamp, itemType, name, id, operation_ParentId, operation_Id, client_Type
| order by timestamp asc
```

client_Type が Browser のデータは、Frontend から Application Insights へ転送されたテレメトリです。
client_Type が PC のデータは、Backend から Application Insights へ転送されたテレメトリです。

下記ドキュメントに記載があるとおり、operation_Id で紐付けされています。
そのため、operation_Id を指定してクエリを実行することで、一気通貫したログが取得できます。

- [Application Insights におけるテレメトリの相関付け](https://docs.microsoft.com/ja-jp/azure/azure-monitor/app/correlation)

Frontend から Backend に対して REST API や GraphQL のクエリを実行する際に、要求ヘッダーに traceparent というデータを渡します。
この traceparent の値が operation_Id となって、Application Insights のテレメトリに紐付けられます。

実際に Edge や Google Chrome の開発者ツールを使ってネットワークをキャプチャーしてみると、traceparent が Frontend から Backend へ渡されているのが確認出来ます。
※ 下図は、Frontend  で収集したネットワーク キャプチャーです。Backend に実装された の GraphQL を呼び出している様子が確認出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192129/bd9328c2-6ff1-917f-0a80-aa5c92344d99.png)

この traceparent は、W3C TraceContext の仕様に基づいて Application Insights SDK が生成しています。

- [Trace Context Level 2](https://w3c.github.io/trace-context/#version-format)

そして traceparent の下記の太字の部分が operation_Id となります。

> traceparent: 00-**efa7e45357f243ecb258176df0a36373**-31323e6cf3bd43d0-01


実際に traceparent の太字の部分をクエリに指定してログを取得すると、下図のように関連付けされていることが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192129/7e7916e6-f0e9-da3c-438a-479799b340db.png)


# 分散トレースを有効化するための JavaScript 側 SDK の設定について
JavaScript 用の Application Insights SDK を組み込む方法に関しては、[こちらのページ](https://docs.microsoft.com/ja-jp/azure/azure-monitor/app/javascript)をご確認ください。
分散トレースを有効にする場合は、下記の設定が必要です。

## 最低限の設定
instrumentationKey 以外に、下記の設定が必ず必要です。
distributedTracingMode と enableCorsCorrelation を、下記の値で追加する必要があります。

```javascript
const appInsights = new ApplicationInsights({ config: {
  instrumentationKey: '06cb6361-b98d-4003-****-************',
  distributedTracingMode: DistributedTracingModes.W3C,
  enableCorsCorrelation : true,
} });
```

上記のように JavaScript 用 Application Insights SDK を設定すると、Frontend から Backend への HTTP 通信時に要求ヘッダーに traceparent が付加されます。
そして Backend に組み込まれた別の Application Insights SDK が転送された traceparent を識別し、operation_Id が付加されたテレメトリを Application Insights リソースへ転送します。


## XHR 以外に FETCH のリクエストも収集したい場合
最低限の設定に、プラスアルファ disableFetchTracking と enableRequestHeaderTracking の設定が必要になります。

```javascript
const appInsights = new ApplicationInsights({ config: {
  instrumentationKey: '06cb6361-b98d-4003-****-************',
  distributedTracingMode: DistributedTracingModes.W3C,
  enableCorsCorrelation : true,
  disableFetchTracking: false,
  enableRequestHeaderTracking: true,
} });
```

GraphQL を使ってデータを取得する場合は、XHR ではなく FETCH が使われます。
JavaScript SDK のデフォルトは、下記のドキュメントに記載があるとおり FETCH を自動収集しません。
そのため、GraphQL の呼び出しも監視したい場合は、明示的に設定する必要があります。

- [Web ページ向けの Application Insights - 構成](https://docs.microsoft.com/ja-jp/azure/azure-monitor/app/javascript#configuration)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192129/54b42f02-8dc9-9612-b154-5a5c3fd29dc9.png)

# 最後に
今回説明した分散トレースは、Application Insights の一部の機能です。
また、ご利用いただいている言語にもよりますがソースコードを変更せずに Application Insights を利用する方法もあります。
他にも色々便利な機能が実装されていますので、興味がある方はぜひご利用ください！

- [Application Insights とは何か?](https://docs.microsoft.com/ja-jp/azure/azure-monitor/app/app-insights-overview)