3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

.NET CoreのコンソールアプリからAzure Application Insightsにログを送信する

Posted at

本記事は.NET Core 3.x以上が対象です。

前置き

C#erなので、小規模なツールやバッチ処理を行うプログラム等を.NET Coreコンソールアプリケーションで作ることがよくあります。
多くの場合、ログはファイルやたまにイベントログに出力したりします。
ただ、アプリケーションで発生したエラーを検知して通知等のアクションを行いたいような場合だと、色々準備する必要があり手間が掛かったりします。
なので、もういっそコンソールアプリのログも全部Azure Application Insightsに送信してしまえばいいじゃん、というのが今回の趣旨です。

Application Insightsとは

私がくどくど書くまでもなく、Azureのドキュメントに書いてありますので、省略。
Application Insights とは何か?

.NET CoreでApplication Insightsにログを送信する方法

TelemetryClientを使って自前で直接送信する方法と、ログプロバイダーを構築してILogger経由で送信する方法があります。
今回はテレメトリというより完全にログなので、後者を選択します。

Application Insightsを作成

AzureポータルからApplication Insightsを作成してください。
Application Insightsにデータを送信するためには、作成後に概要画面に表示されるインストルメンテーションキーが必要となります。

コードを書いてみる

汎用ホストは使わずに構成をしてみます。
まずはnugetで Microsoft.ApplicationInsights.WorkerService をインストールします。
その後、以下のような感じでコードを書いてみました。

static async Task Main(string[] args)
{
    IServiceCollection services = new ServiceCollection();
    services.AddLogging(builder =>
    {
        // ログのフィルタを構成
        builder.AddFilter<Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider>("", LogLevel.Information);
    });
    services.AddApplicationInsightsTelemetryWorkerService("<Replace with your instrumentation key>");

    // テレメトリチャネルをInMemoryChannelに設定
    services.Configure<TelemetryConfiguration>(
        (config) => { config.TelemetryChannel = new InMemoryChannel(); });

    // サービスプロバイダーを構築
    IServiceProvider serviceProvider = services.BuildServiceProvider();
    // Loggerを取得
    ILogger<Program> logger = serviceProvider.GetRequiredService<ILogger<Program>>();
    // テレメトリクライアントを取得
    var telemetryClient = serviceProvider.GetRequiredService<TelemetryClient>();

    try
    {
        logger.LogInformation("Program start.");
        await DoWork();
        logger.LogInformation("Program end.");
    }
    catch (Exception e)
    {
        logger.LogError(e, "Program error!");
    }
    finally
    {
        telemetryClient.Flush();
    }
}

コード内を見ていきます。

IServiceCollection services = new ServiceCollection();
services.AddLogging(builder =>
{
    // ログのフィルタを構成
    builder.AddFilter<Microsoft.Extensions.Logging.ApplicationInsights.ApplicationInsightsLoggerProvider>("", LogLevel.Information);
});
services.AddApplicationInsightsTelemetryWorkerService("<Replace with your instrumentation key>");

まず、ServiceCollectionを作成してログのフィルタを設定してログレベルをInformationに設定しています。
その後、Application Insightsのインストルメンテーションキーを渡して送信できるように構成させます。

// テレメトリチャネルをInMemoryChannelに設定
services.Configure<TelemetryConfiguration>(
    (config) => { config.TelemetryChannel = new InMemoryChannel(); });

「テレメトリチャネルをInMemoryChannelに設定」と書いている部分では、Application Insightsのテレメトリチャネルをデフォルトの物から変更しています。
何も指定しない場合、テレメトリチャネルはServerTelemetryChannelとなります。再試行に優れた高度なチャネルなのですが、テレメトリの送信が同期的には行われなくなります。ASP.NET Coreアプリケーションのような動作し続けている物なら問題ありませんが、コンソールアプリケーションのように明確に(割と素早く)終了するアプリケーションでは、送信が行われる前にプログラムが終了してしまい、ログが送られないままになってしまう場合が多いです。
InMemoryChannelはServerTelemetryChannelに比べて軽量かつ再試行性が劣りますが、メモリ内にバッファリングしているため同期的なテレメトリの送信が可能です。

// サービスプロバイダーを構築
IServiceProvider serviceProvider = services.BuildServiceProvider();
// Loggerを取得
ILogger<Program> logger = serviceProvider.GetRequiredService<ILogger<Program>>();
// テレメトリクライアントを取得
var telemetryClient = serviceProvider.GetRequiredService<TelemetryClient>();

そして、上記の設定が終わったので、サービスプロバイダーを構築してLoggerインスタンスを取得し、同様にTelemetryClientを取得します。(当然、先ほど設定したInMemoryChannelが取得されます)

telemetryClient.Flush();

その後は適当にログを出力し、最後に上記で取得したTelemetryClientからFlushを呼び出してデータの送信を行って終了です。
上記の通りInMemoryChannelにしているため、Flushで同期的にテレメトリが送信されます。

出力されたログを確認してみる

AzureポータルのApplication Insightsから送信されたのログを見てみます。
監視カテゴリ内のログからLog Analyticsの画面を開き、tracesの内容を表示させます。
image.png

コード内で送信させたログメッセージが確認できました。
image.png

コード内で例外を発生させた場合も確認してみます。今度はexceptionsの内容を表示させます。
例外が記録されていることも確認できました。
image.png

あとがき

割と少ないコード量でコンソールアプリからApplication Insightsにログが送れました。
ただ、このコードだけだとログのフィルタリング設定など、設定ファイル等で変更したいような内容までコード内で設定しているので、あまり使い勝手がよくありません。
このことは若干趣旨がずれるので、この辺を解消する方法は別途書きたいと思っています。

参考ページ

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?