ちょっとだけ Inside Application Insights SDK (.NET)
ちょっとだけ Inside Application Insights SDK (.NET)
Application Insights の使い方じゃなくて、Application Insights SDK (.NET) がどうやってテレメトリを送信しているかです。
概要
大雑把にこんな感じです。
[Telemetry Client] --> [Telemetry Initializers] --> [Telemetry Processors] --> [Telemetry Channel] --> [Application Insights サーバー]
Telemetry Client を使って直接テレメトリを送信することもできますが、明示的に書かなくてもある程度は何とかなります。
Microsoft.Extensions.Logging
.NET 公式のロギングフレームワークは次のようにすることで、ログをトレーステレメトリとして Application Insights に送信します。
実装は ApplicationInsightsLogger にあります。一部抜粋しますが、受け取ったログを Telemetry Client を用いて送信しているのが分かります。
this.telemetryClient.TrackTrace(traceTelemetry);
Telemetry Collector
.NET で HTTP リクエストを送信すると、Application Insights のポータルで、リクエスト URL やレスポンスコードを確認することができます。それを担っているのが HttpCoreDiagnosticSourceListener という Telemetry Collectorです。(多分)
パフォーマンスカウンターや ASP.NET Core にリクエスト処理などのテレメトリもそれぞれ Telemetry Collector があります。
Telemetry Collector は情報を集めた後、Telemetry Client を用いてテレメトリを送信します。
テレメトリの送信
Telemetry Client に送信したテレメトリは直接 Application Insights に送信されません。前述したように間にいくつかのインスタンスで処理されます。だいたいこんな感じです。
+------------------+
| | --> [Telemetry Initializer A]
| | --> [Telemetry Initializer B]
| | --> [Telemetry Initializer C]
| Telemetry Client |
| | --> [Telemetry Processor A]
| | +--> [Telemetory Processor B]
| | +--> [TransmissionProcessor]
| | +--> [Telemetry Channel]
| | +--> [Application Insights Server]
+------------------+
Telemetry Initializer
Telemetry Client は、まずは登録されているすべての Telemetry Initializer に対してテレメトリを渡します。主にテレメトリの加工に使います。しょっちゅう使うので、最初に覚えておくといいでしょう。
登録された Telemetry Initializer が順次呼び出され、テレメトリを加工します。
public void ConfigureServices(IServiceCollection services)
{
// services.AddSingleton<ITelemetryInitializer, CustomTelemetryInitializer>();
// 何度も同じのが登録されるのを防ぐ書き方
services.TryAddEnumerable(
ServiceDescriptor.Singleton<ITelemetryInitializer, CustomTelemetryInitializer>()
);
}
class CustomTelemetryInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry item)
{
item.Context.User.AuthenticatedUserId = "taro";
}
}
標準で様々な Telemetry Initializer が登録されています。
- ComponentVersionTelemetryInitializer - アプリケーションバージョンを埋め込む
-
AspNetCoreEnvironmentTelemetryInitializer - 環境名 (
DevelopmentとかProductionとか) を埋め込む
Telemetry Processor
すべての Telemetry Initializer を通して加工が済んだテレメトリは、Telemetry Client によって Telemetory Processor に渡されます。
最終的に TransmissionProcessor が呼び出されます。このプロセッサーが Telemetry Channel にテレメトリを送信しています。
public void Process(ITelemetry item)
{
TelemetryDebugWriter.WriteTelemetry(item);
this.sink.TelemetryChannel.Send(item);
}
Telemetry Processor は Decorator Pattern になっていて、次のコード例のように値を加工することができます。(テレメトリの加工自体は Telemetry Initializer で行った方がいいですが)
public void ConfigureServices(IServiceCollection services)
{
services.AddApplicationInsightsTelemetryProcessor<CustomTelemetryProcessor>();
}
class CustomTelemetryProcessor(ITelemetryProcessor next) : ITelemetryProcessor
{
public void Process(ITelemetry item)
{
item.Context.User.AuthenticatedUserId = "taro";
next.Process(item);
}
}
Telemetry Processor の本当の目的はテレメトリのフィルタリングです。次の Telemetry Processor を呼び出さなければ、そこで処理は終了し、テレメトリが送信されることはありません。
Application Insights はデータを間引いてサンプリングをします。公式で用意されている SamplingTelemetryProcessor はサンプリングをする Telemetry Processor の実装です。
一部抜粋しますが、サンプリングされたデータを次の Telemetry Processor に回すような処理が書かれています。(実際はもっと複雑ですし、サンプリングを行うほかの実装もあるようです)
if (isSampledIn)
{
if (advancedSamplingSupportingTelemetry != null)
{
this.HandlePossibleProactiveSampling(item, samplingPercentage, advancedSamplingSupportingTelemetry);
}
else
{
this.SampledNext.Process(item);
}
}
なお、Telemetry Initializer は機構上非同期処理ができません。非同期処理をする場合は Telemetry Processor を利用します。
void Process(ITelemetry item)
{
Task.Run(() => ProcessAsync(item));
}
async Task ProcessAsync(ITelemetry item)
{
var user = await GetUserAsync();
item.Context.User.AuthenticatedUserId = user.Id;
next.Process(item);
}
Telemetry Channel
Telemetry Channel はテレメトリを貯めこんでおいて、あとでまとめて Application Insights サーバーに送信するのが目的です。通常は ServerTelemetryChannel が使われるようです。
Telemetry Channel を独自実装に切り替えることもできます。ITelemetryChannel インターフェイスを実装したカスタムクラスを登録するだけです。
Application Insights には送信しないテスト用の Telemetry Channel や、Application Insights でない類似サービスにテレメトリを送るなんてこともできます。
最後に
Application Insights SDK (.NET) の大体の仕組みはこんな感じです。いろんな要求に耐えられるように、ぱっとはわかりにくい仕組みになっています。特に、テレメトリを生成したのがどの Telemetry Collector なのかを調べるのは大変です。
カスタムの Telemetry Initializer を作成し登録し、Initialize() メソッドにブレークポイントを仕掛けてデバッガーで止め、スタックトレースを追いかけていけば、テレメトリを生成している Telemetry Collector が分かります。
こういう拡張性の高い仕組みは初見は難しく感じますが、わかってしまえばそうでもありません。むしろ、いろんな拡張ができるのでありがたいです。
Discussion