ASP.NET Core MVC - Serilogを使ってファイルにログ出力する

ASP.NET Core MVCでSerilogを使ってファイルにログ出力するサンプルを書いてみました。

Serilog — simple .NET logging with fully-structured events

サンプルでは次のことを実現しています。

  • ログをファイルに出力する
  • 日付ごとにログファイルを作成する
  • ログの中身をJSON形式にする
  • appsettings.jsonを参照してロガーを構築する

それではコードを見ていきましょう。

Serilogをインストールする

まずはNuGetで必要なパッケージをインストールします。

Install-Package Serilog
Install-Package Serilog.AspNetCore
Install-Package Serilog.Formatting.Compact
Install-Package Serilog.Settings.Configuration
Install-Package Serilog.Sinks.File

パッケージ名から想像できるかもしれませんが、それぞれのパッケージの役割は次のような感じです。

パッケージ 説明
Serilog 本体
Serilog.AspNetCore ASP.NET Core用(WebHostBuilderのUseSerilog)
Serilog.Formatting.Compact ログのJSON形式出力
Serilog.Settings.Configuration appsettings.jsonから設定を読み込む
Serilog.Sinks.File ログのファイル出力(日付ごとのログファイル作成もこれ)

今回のサンプルでは使っていませんが以下もよく使いそうですね。

パッケージ 説明
Serilog.Sinks.Console ログのコンソール出力
Serilog.Sinks.Debug ログのデバッグ出力

ログ出力の準備をする

一旦appsettings.jsonのことは忘れて、まずはコードでログ出力の準備をしたいと思います。

公式のサンプルなどを見ているとWebHostを構築する前にロガーを準備するといいようで、Programクラスを次のような感じにします。

public class Program {
    public static void Main(string[] args) {
        // ロガーを構築する
        Log.Logger = new LoggerConfiguration()
            // ファイルに書き込む
            .WriteTo.File(
                // JSON形式で出力
             formatter: new CompactJsonFormatter(),
             path: @".\log\webapp.txt",
             restrictedToMinimumLevel: LogEventLevel.Information,
                // 日付ごとに新しいファイルを作る
             rollingInterval: RollingInterval.Day)
            .CreateLogger();

        try {
            Log.Information("Starting Web Host");

            CreateWebHostBuilder(args)
                .Build()
                .Run();
        } catch (Exception exception) {
            Log.Fatal(exception, "Host terminated unexpectedly");
        } finally {
            Log.CloseAndFlush();
        }
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            // ログプロバイダーとしてSerilogを使う
            .UseSerilog();
}

コントローラでログを出力する

コントローラのアクションでログを出力するコードを書き足します。

public class HomeController : Controller {
    private readonly ILogger _logger;

    public HomeController(ILogger<HomeController> logger) {
        _logger = logger;
    }

    public IActionResult Index() {
        // ログを出力
        _logger.LogInformation(
            "Log {@param}",
            new { controller = "Home", action = "Index" });

        return Content("Home.Index");
    }
}

これでアクションを呼び出すとログが出力されるようになりました。

指定した出力先にwebapp20181205.txtといった日付を含んだ名前のファイルが作成されます。また出力されるログの中身は整形すると次のようなものです。

{
    "@t": "2018-12-05T02:18:12.3417756Z",
    "@mt": "Log {@param}",
    "param": {
        "controller": "Home",
        "action": "Index"
    },
    "SourceContext": "WebApp.Controllers.HomeController",
    "ActionId": "",
    "ActionName": "WebApp.Controllers.HomeController.Index (WebApp)",
    "RequestId": "",
    "RequestPath": "",
    "CorrelationId": null,
    "ConnectionId": ""
}

appsettings.jsonを参照する

今度はappsettings.jsonから設定を読み込んで上記と同じロガーを構築したいと思います。

appsettings.jsonを作成して、公式を参考にしながら設定を書いていきます。formatterを指定する方法に悩みましたが多分これでいいはずです。

{
    "Serilog": {
        "Using": [
            "Serilog.Sinks.File",
            "Serilog.Formatting.Compact"
        ],
        "WriteTo": [
            {
                "Name": "File",
                "Args": {
                    "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact",
                    "path": ".\\log\\webapp.txt",
                    "restrictedToMinimumLevel": "Information",
                    "rollingInterval": "Day"
                }
            }
        ]
    }
}

Programクラスのロガーを構築する部分は、設定ファイルを読み込むように変更します。

// appsettings.jsonを読み込む準備
var config = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json")
    .Build();

// ロガーを構築する
Log.Logger = new LoggerConfiguration()
    .ReadFrom.Configuration(config)
    .CreateLogger();

これでアクションを呼び出すとさっきと同じようなログが出力されます。

おしまい。