yotiky Tech Blog

とあるエンジニアの備忘録

WPF から Application Insights に Telemetry を送信する

目次

Application Insights

Application Insights は Azure Monitor の機能であり、開発者や DevOps プロフェッショナル向けの拡張可能なアプリケーション パフォーマンス管理 (APM) サービスです。 このサービスを使用して、実行中のアプリケーションを監視することができます。 パフォーマンスの異常を自動的に検出し、組み込まれている強力な分析ツールを使用して、問題を診断し、ユーザーがアプリを使用して実行している操作を把握できます。 Application Insights は、パフォーマンスやユーザビリティを継続的に向上させるうえで役立つように設計されています。 オンプレミス、ハイブリッド、または任意のパブリック クラウドでホストされている .NET、Node.js、JavaPython などのさまざまなプラットフォーム上のアプリで機能します。 DevOps プロセスと統合され、さまざまなツールへの接続ポイントを備えています。 Visual Studio App Center と統合することで、モバイル アプリからテレメトリを監視および分析できます。

docs.microsoft.com

Application Insights は、Azure プラットフォーム上に限った話ではなく、ASP.NET/ASP.NET Core Web アプリケーション以外に JavaJavaScript、Node.JS、Pyhon などの言語や、AndroidiOS向けにもSDKが提供されています。

今回は、WPF から Telemetry を送信する方法を紹介します。

非HTTPアプリケーション向け

docs.microsoft.com

上記サイトでは、Webアプリケーション以外の3種類のアプリケーションについて説明しています。

  1. .NET Core 3.0 ワーカーサービス
    .NET Core 3.0 でマイクロサービス関連のバックグラウンド処理を目的とした Worker Service プロジェクトが追加されました。実行時間が長いサービスを、Windows サービスとして実行します。

  2. IHostedService を使用した ASP.NET Core のバックグラウンドタスク .NET Core 2.0 以降 IHostedService が提供され、バックグラウンドプロセスで処理するタスクを簡単に実装できるようになっています。

  3. .NET Core / .NET Framework コンソール アプリケーション .NET Core 2.0 以上、もしくは .NET Framework 4.7.2 以上で利用できます。コンソールアプリケーションとなっていますが、WPFでも使用可能です。

検証環境

手順

パッケージのインストール

NuGet で Microsoft.ApplicationInsights.WorkerService をインストールします。 間違えずに WorkerService が付いているものを選びます。

実装

まずは全文です。

IServiceCollection services = new ServiceCollection();
services.AddLogging(builder => builder.AddFilter<ApplicationInsightsLoggerProvider>("WpfApp1", LogLevel.Information));
services.AddApplicationInsightsTelemetryWorkerService("instrumentationkeyhere");

IServiceProvider serviceProvider = services.BuildServiceProvider();
var logger = serviceProvider.GetRequiredService<ILogger<SampleClass>>();
var telemetryClient = serviceProvider.GetRequiredService<TelemetryClient>();

var httpClient = new HttpClient();

// 実際はTelemetryを送信する期間≒アプリケーションのライフサイクルに合ったロジックが必要
//while (true) 
{
    logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);

    using (telemetryClient.StartOperation<RequestTelemetry>("operation"))
    {
        logger.LogWarning("A sample warning message. By default, logs with severity Warning or higher is captured by Application Insights");
        logger.LogInformation("Calling bing.com");
        var res = await httpClient.GetAsync("https://bing.com");
        logger.LogInformation("Calling bing completed with status:" + res.StatusCode);
        telemetryClient.TrackEvent("Bing call event completed");
    }

    await Task.Delay(1000);
}

telemetryClient.Flush();
Task.Delay(5000).Wait();


続けて細部を見ていきます。

IServiceCollection services = new ServiceCollection();
services.AddLogging(builder => builder.AddFilter<ApplicationInsightsLoggerProvider>("WpfApp1", LogLevel.Information));
services.AddApplicationInsightsTelemetryWorkerService("instrumentationkeyhere");

ServiceCollection は、Microsoft.Extensions.DependencyInjection 名前空間にあるDIコンテナです。 そこに ApplicationInsightsLoggerProvider を使用して、ILogger のログをキャプチャするように設定します。

ILoggingBuilder でフィルターを追加しています。後で Logger を取得する時に Type をカテゴリ名として指定しますが、その Type の FullName のプレフィックスと一致させることで、出力するログレベルを制御することができます。

今回はアプリケーションの名前空間Wpf1App であり SampleClass もその配下に定義されています。また、LogLevelInformation なので、Information 以上の Level のログが出力されることになります。 一致するフィルターがない Logger の場合は、既定値の Warning 以上のログが出力されるようになります。

"instrumentationkeyhere" はよしなに取得、設定するようにして下さい。


ILogger のログをキャプチャする必要がなく、 TelemetryClient だけを使用する場合はよりシンプルになります。必要なのは次のコードの部分だけです。

IServiceCollection services = new ServiceCollection();
services.AddApplicationInsightsTelemetryWorkerService(key);

IServiceProvider serviceProvider = services.BuildServiceProvider();
var telemetryClient = serviceProvider.GetRequiredService<TelemetryClient>();


次に、ServiceProvider をビルドして、Loggerインスタンスを取得します。

IServiceProvider serviceProvider = services.BuildServiceProvider();
var logger = serviceProvider.GetRequiredService<ILogger<SampleClass>>();
var telemetryClient = serviceProvider.GetRequiredService<TelemetryClient>();

カテゴリ名として指定する Type は、Application Insights にもカテゴリとして出力されます。 ILogger に定義されている汎用的なログ出力以外に、Application Insights で使われる詳細なログを出力するために、TelemetryClient を使います。


残りの後半部分についてです。

RequestTelemetryusing で囲ったログと依存関係が収集され親子関係を持つログとして関連付けられます。依存関係はログだけでなく、外部コンポーネント、つまりHTTP を使用して呼び出されるサービス、またはデータベース、あるいはファイル システムも追跡されます。追跡される依存関係をいかに示します。 また、StartOperation() を使う方法は、依存関係を手動で追跡する方法に該当します。

依存関係 詳細
Http/Https ローカルまたはリモートの http/https 呼び出し
WCF 呼び出し Http ベースのバインディングを使用する場合にのみ自動追跡されます。
SQL SqlClient で行われる呼び出し。 SQL クエリのキャプチャについてはこちらを参照してください。
Azure Storage (BLOB、テーブル、キュー) Azure Storage Client で行われる呼び出し。
EventHub Client SDK バージョン 1.1.0 以上。
ServiceBus Client SDK バージョン 3.0.0 以上。
Azure Cosmos DB HTTP/HTTPS が使用されている場合にのみ、自動的に追跡されます。 TCP モードは、Application Insights ではキャプチャされません。

Application Insights での見え方は、後段の実行結果を確認してみてください。 「DEPENDENCY」として登録されているデータが追跡結果になります。

docs.microsoft.com

アプリケーションを終了する場合は、Telemetry が送信完了するために Flush() を呼び出す必要があります。通常は、30秒毎、または500アイテムが溜まってからデータを送信するようです。

実行結果

サンプルコードの出力結果です。

f:id:yotiky:20201118012613p:plain

以下は、RequestTelemetry の詳細です。 タイムラインで処理時間を見ることができます。また、RequestTelemetry で囲った内容だけが集約されているのが分かります。

f:id:yotiky:20201118014009p:plain f:id:yotiky:20201118013915p:plain

一致するフィルタがない場合は、 Warning 以上が出力されるようになります。

f:id:yotiky:20201118000223p:plain