しばやん雑記

Azure とメイドさんが大好きなプログラマーのブログ

Azure Functions の監視を OpenTelemetry ベースに移行する

少し前に Application Insights SDK のバージョン 3.0 がリリースされて、内部実装が OpenTelemetry ベースに移行されました。基本的には OpenTelemetry Distro を直接使う方法が推奨されていますが、Application Insights SDK のアップデートだけで OpenTelemetry 対応できるのはメリットがあります。

それに伴って Azure Functions の .NET Isolated で使われている Application Insights SDK の一つである Microsoft.ApplicationInsights.WorkerService もバージョン 3.0 になりました。1 つのソリューションで Azure Functions と ASP.NET Core プロジェクトを管理している場合、同時にアップデートすることも多そうです。

通常の .NET Worker アプリケーションの場合は特に問題ないのですが、Azure Functions の場合は素直にアップデートすると実行時に以下のような例外が発生するようになります。ビルドは問題なく通るので注意が必要です。

これは Azure Functions の Application Insights 組み込みに必要な Microsoft.Azure.Functions.Worker.ApplicationInsights パッケージが v2 系の SDK に強く依存しているため発生します。このパッケージが v3 SDK 向けにアップデートされると問題ないのですが、GitHub の Issue 上で v3 向けのパッケージは提供予定がないらしいので、将来的には OpenTelemetry ベースに移行する必要があります。

現在では Azure Functions も OpenTelemetry をサポートするようになっていますが、テンプレートから作成した場合は Application Insights SDK が使われるので導入は少し作業が必要です。手順としては以下のドキュメントを参照してもらえれば問題ないですが、実際に移行したところ少しはまった部分がありました。

まずは既存の Azure Functions プロジェクトを確認すると、以下の 2 つの Application Insights 関係のパッケージがインストールされているはずなので削除します。この 2 つは Application Insights SDK に依存するパッケージなので必要ありません。

  • Microsoft.ApplicationInsights.WorkerService
  • Microsoft.Azure.Functions.Worker.ApplicationInsights

その代わりに以下の 3 つの OpenTelemetry 関係のパッケージを追加でインストールします。ASP.NET Core の場合は 1 つのパッケージで済むのですが、Azure Functions の場合は個別に入れる必要があります。

  • Microsoft.Azure.Functions.Worker.OpenTelemetry
  • Azure.Monitor.OpenTelemetry.Exporter
  • OpenTelemetry.Extensions.Hosting

ここまでの対応でビルドが通らなくなっているはずなので、Program.cs にあるApplication Insights の初期化コードを削除して以下のように置き換えます。カスタマイズが必要な場合は UseAzureMonitorExporter の引数で行えます。

using Azure.Monitor.OpenTelemetry.Exporter;

using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Azure.Functions.Worker.OpenTelemetry;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = FunctionsApplication.CreateBuilder(args);

builder.ConfigureFunctionsWebApplication();

builder.Services.AddOpenTelemetry()
    .UseFunctionsWorkerDefaults()
    .UseAzureMonitorExporter();

builder.Build().Run();

これでビルドが通るようになるので実行して確認すればよいのですが、そのままローカル開発環境でデバッグ実行すると Application Insights の接続文字列が存在しないというエラーが出て起動に失敗します。Application Insights SDK の場合は接続文字列が存在しない場合は自動でオフになっていたのですが、OpenTelemetry Distro では必須になったようです。

ローカル開発環境でも Application Insights を必須にするのは避けたいので、デバッグ実行の場合はプリプロセッサで無効化するなどの対応が必要になります。個人的にはプリプロセッサで無効化するのは using 周りが残って気持ち悪いので、以下のようにダミーの接続文字列を追加して対応しました。

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
    "APPLICATIONINSIGHTS_CONNECTION_STRING": "InstrumentationKey=00000000-0000-0000-0000-000000000000"
  }
}

これでローカル開発環境でも正しく起動できるようになったので、最後に実際に Application Insights に接続してテレメトリが送信されているかを確認します。プロパティ名が OpenTelemetry のスキーマに従ったものになっていることが確認できますが、Azure Functions Host が生成したものについてはこれまで通りです。

実際に Acmebot に対して OpenTelemetry ベースへの移行を行った Pull Request が以下になります。作業内容としてはシンプルで ITelemetryInitializer の削除などを行っていますが、同等の機能が組み込まれているので必要なくなりました。

これ以上に ITelemetryProcessor などでカスタマイズしているアプリケーションを OpenTelemetry に移行するのは手間がかかりますが、フィルタリング周りを含め以降は出来そうなので、時間があれば追加でブログに書こうかと思います。