Azure Functions を Application Insights で監視する（V2、JavaScript版）

# はじめに
[Microsoft Azure Tech Advent Calendar 2018](https://qiita.com/advent-calendar/2018/microsoft-azure-tech) の 18 日目。
Azure Functions の開発／運用時に必要不可欠な Application Insights で監視する方法を紹介する。**手のかからないサーバーレスこそ監視が重要。**
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29416/6e30437e-c5ce-b48b-d3a1-414469174e3e.png)
主に以下のユースケースについて紹介する。

- 開発時にリアルタイムでログをモニタリングし、必要に応じてフィルタリングする。  
    - => Live Metrics Stream で実現する。
- Functions からの外部依存（Queue、Cosmos DB、外部 API など）
    - => Application Map で実現する。


多くの情報は下記の公式ドキュメントにさらっと書いてあることの解説である。
[Azure Functions を監視する](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-monitoring)

## 前提条件

以下の環境で確認した。

- Functions は V2。Runtime version: 2.0.12246.0 (~2)
- Functions ランタイム言語は JavaScript
    - Application Insights JavaScript SDK: version 1.0.8
    - 本記事の内容は、C# でも全く同等のことができるため（むしろ SDK が充実しているぶん高機能である）JavaScript である必要は全くない。

## 準備
### Functions を作成する
どんな構成でも構わないが、今回は以下のような依存関係がある Azure Functions を作成した。監視部分を検証するだけであれば実装の中身は必要なく、バインドで繋げるだけで本記事の内容は検証可能であるはず。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29416/a4e8295c-240b-1af1-79b3-c029a87ee681.png)

- In: Timer Trigger, Out: Queue Output
- In: Queue Trigger, Out: Cosmos DB

### Application Insights を有効にする
詳細は、[こちらの公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-monitoring#enable-app-insights-integration) のとおりだが、

- Functions 新規作成時に ON にしておくのが手っ取り早い。
- 作成した後からでも有効にできる。  
    1. Application Insights の `APPINSIGHTS_INSTRUMENTATIONKEY` をFunctions のアプリケーション設定 AzureWebJobsDashboard に追加して、
    2. 組む組み込みログを無効にすればよい。アプリケーション設定 `AzureWebJobsDashboard` を削除する。

# やっと本題。監視する
## Live Metrics Stream: リアルタイムでログを見る
主に開発時に使うことになる。Functions 画面に出てくるこのログでも監視できないことはないが、以下の点で非常につらい。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29416/e7590371-6d8c-1484-9da7-65a6cb275443.png)

* UI の構造上、 **一つの Functions 単体のログしか見れず**、複数の Functions を横断してデバッグできない。
* Functions 実行ホストで発生しているイベントなどが見れない。新たなコードがデプロイされる際に発生する
* フィルタできない。

ということで、**Application Insights の Live Metrics Stream を使う**。これがないときつい。
Application Insights の左メニューから、 Live Metrics Stream を選択する。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29416/a6f24fa2-33be-a6e9-1b4b-fdad454e8ba3.png)

Sample Telemetry を見ながらこのあたりかな、というところで Pause ボタンで一時停止したり、フィルタボタンから、どれかの Functions にターゲットして確認、などができる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29416/85e0742f-8f1c-3542-fbd0-71028388e6d1.png)

Sample Telemetry のフィルタボタンから、**Functions 名は Trace ログの Category プロパティに入っているので**、下記のように Custom Dimension でフィルタリングすると、特定の Functions のみログが見ることができる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29416/9c971f9d-5229-d380-29bf-53ddc52732e6.png)
他にも、InvocationId でフィルタリングすることで、ある特定の実行だけにフィルタしたりすることができる。

便利！というかこれ無しでどうやって開発するかわからない。。

## Application Map: 依存関係を分散トレーシング
役割は見た目のとおりだが、Functions アプリの依存関係を可視化してどこがボトルネックになっているか、など直観的にわかる。分散トレーシングといった言葉のほうが伝わりやすいかもしれない。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29416/89d6f999-435b-0e2a-1497-0a12571f40d3.png)

下記の公式ドキュメントのとおり、以下の依存関係は明示的な実装をせずとも、勝手にこのマップを作ってくれる。
> [Application Insights の設定: 依存関係の追跡](https://docs.microsoft.com/ja-jp/azure/application-insights/app-insights-asp-net-dependencies) 
> 
> - SQL データベース
> - HTTP ベースのバインドを使用する ASP.NET Web および WCF サービス
> - ローカルまたはリモートの HTTP 呼び出し
> - Azure Cosmos DB、テーブル、Blob Storage、およびキュー

また、対象の Functions を選択すると右側に、"Investigate Performance" などとサジェストしてくれるので、クリックすると、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29416/96a97ce9-f2c4-cdfb-31ce-7387ba1cdc93.png)

どの Functions が時間かかっているか、Dependencies で どの依存関係が時間かかっているか、あたりを表示してくれる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29416/5c15881f-2090-d4a7-70b5-2a126e3d8a1b.png)

### 独自の依存関係
その他、独自の外部 API をコールするケースなど、独自のモジュールに依存関係を設定したい場合は以下のような実装をすればよい。

```js
const appInsights = require("applicationinsights");
appInsights.setup();
const client = appInsights.defaultClient;

module.exports = async function (context, myTimer) {
    var startTime = new Date().getTime();

    try
    {
        // call external API, etc.
    }
    finally
    {
        var elapsed = new Date() - startTime;
        client.trackDependency(
            {
                target: "External API",
                name: "func01 to queue01", 
                data: "push message to queue", 
                duration: elapsed, 
                resultCode: 0, 
                success: true,
                dependencyTypeName: "EXT API",
                tagOverrides: {
                    "ai.operation.id": context.invocationId
                }
            }
        );
    }
};
```
記述量が多いのは残念だが、下記のように独自の依存関係を作れた。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29416/1ee6eaa9-bf0d-3a8a-13c9-cc9f4c53cb00.png)
上記、デフォルトで表示される Functions アプリと、インスタンスが分かれて表示されてしまうのは、少し頑張ってみたが、まだ対応されていない模様。（上記 Queue や Cosmos DB と同じ列に並べてほしい。）

詳細は下記の公式ドキュメントを参照のこと。

* [JavaScript 関数でのカスタム テレメトリ](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-monitoring#custom-telemetry-in-javascript-functions)
* https://github.com/Microsoft/ApplicationInsights-node.js （README により詳細な情報とソースコード）

## Search: ログをクエリして、End-to-End なトランザクションを確認する
こちらは名前のとおりで、過去のログからトラブルシューティング、といったように運用で使われることが多いだろう。
Application Insights 左メニューより "Search" を選択する。この時点では何もクエリされないので、手っ取り早く、"Click here to see all data in the last 24 hours" からまずはデータを表示させてしまってから、絞り込むとよい。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29416/9a1ee6cf-ba12-a633-3d59-a79efb510f73.png)
まずは24時間ぶんの全てを表示する。さらに、横軸時系列の部分はドラッグで範囲指定が可能。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29416/aa7ab053-6718-175d-f3f1-319a54b10494.png)
ここでまた一つ便利機能だが、End-to-end transaction details というビューがあり、どれか任意の Trace ログあたりを選択すると、そのオペレーションで実行された（Functions であれば大抵1実行）ログをまとめて見れる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/29416/9794b2bb-79cc-d070-c0a6-6b0817f6a357.png)
左 telemetry 表示 と、右 timeline 表示を行ったり来たりしながら、「このステップで時間がかかっているな」はすぐにわかってしまう。右 timeline 表示は、ブラウザの開発者ツールなんかでよく見る UI。

もちろん、通常の使い方として、クエリで狙い撃ちしてもよい。狙い撃ちして1行見つけたあとに、上記のようにオペレーションあたりのエンドツーエンドがすぐに確認できるということ。

# まとめ
Application Insights なくしては Functions の実装＆運用効率が桁違いである。
多くの機能は、Application Insights 統合を ON にするだけで有効になるため、**あとは上記のような使い方を覚えるだけ**である。

# 参考
- [Azure Functions の JavaScript 開発者向けガイド](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-reference-node#using-scriptfile)
    - フォルダー構造  
    Application Insights のモジュールは原則全ての Functions で使うことになるはずなので、全ての関数から使えるように。全ての Functions の中で `npm install applicationinsights` などは避ける。
- [Azure Functions における Azure Queue Storage のバインド](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-storage-queue)
- [Azure Functions 2.x の Azure Cosmos DB バインド](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-reference-node#using-scriptfile)
- https://github.com/Microsoft/ApplicationInsights-node.js