銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

ASP.NET 5 の Logging について

ASP.NET Advent Calendar 6日目です。

qiita.com

ASP.NET 5 でLoggingの機能が一新されます。今日は簡単に紹介したいと思います。なお下記のドキュメントを参考にしつつ、コードは ASP.NET RC1 時点のものを参照しているため、Nugetのパッケージ名など一部が変更されています*1

Logging — ASP.NET 0.0.1 documentation

Loggingするには

Loggingのインターフェース自体はおそらく .NET Coreでも使われると思われますが*2、ASP.NET においてはDIによるLoggerの注入が前提となっています。ILoggerFactory を注入してCreateLoggerするか ILogger もしくは ILogger を直接注入します。

public class HomeController : Controller
{
    private ILogger<HomeController> logger;

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

    public IActionResult Index()
    {
        logger.LogInformation("Home");
        return View();
    }
}
public class HomeController : Controller
{
    private readonly ILogger logger;

    public HomeController(ILoggerFactory loggerFactory)
    {
        logger = loggerFactory.CreateLogger<HomeController>();
    }

    public IActionResult Index()
    {
        logger.LogInformation("Home");
        return View();
    }
}

DIにより取得するので一番わかりやすいControllerでサンプルを書きました。じゃあ、それ以外のDIではなくインスタンス生成されるクラスでロギングしたい場合はどうするか?という点についてはあまり情報がなく、ILoggerFactoryを引き回して渡すか、コンストラクタ経由の注入ではなく別の方法でILoggerFactoryのインスタンスを取得するか、になるのではないでしょうか。ただ後者については、現時点でのドキュメントには方法が書いておらず、自分が調べた範囲でもどうやるかはわからないままです。

Dependency Injection — ASP.NET 0.0.1 documentation

Loggingの構成と出力のカスタマイズ

Startup.Configure メソッドで引数に渡されるILoggerFactory に対してメソッドを呼び出すことで設定を行います。ConsoleやDebug、TraceListenerやEventLogへ出力するためのライブラリが標準で提供されているので、project.json に追加して設定を行います。

  "dependencies": {
    "Microsoft.Extensions.Logging": "1.0.0-rc1-final",
    "Microsoft.Extensions.Logging.Console": "1.0.0-rc1-final",
    "Microsoft.Extensions.Logging.Debug": "1.0.0-rc1-final",
    "Microsoft.Extensions.Logging.TraceSource": "1.0.0-rc1-final",
  }

ただ、TraceListenerやEventLogはDNX Coreではサポートしていないので、ifディレクティブなどと併用する必要があります。

            loggerFactory.AddDebug();
            loggerFactory.AddConsole();
#if DNX451
            var sourceSwitch = new SourceSwitch("LoggingSample");
            loggerFactory.AddTraceSource(sourceSwitch,
                 new ConsoleTraceListener(false));
            loggerFactory.AddTraceSource(sourceSwitch,
                new EventLogTraceListener("Application"));
#endif

自前で出力先を追加したい場合は、ILoggerを継承して出力を行うクラスに加えて、仲介するためのILoggerProviderを継承したクラスを作成したうえで、AddDebug, AddConsoleのように ILoggerFactoryを第一引数として受け取り必要な設定を行うための拡張メソッドを用意するのが推奨されています。既存の拡張を参考にするとわかりやすいでしょう。

Logging/src/Microsoft.Extensions.Logging.Debug at 1.0.0-rc1 · aspnet/Logging · GitHub

Logging/src/Microsoft.Extensions.Logging.Console at 1.0.0-rc1 · aspnet/Logging · GitHub

ファイル出力をしたい場合は...?

GitHubのIssueでNLogもしくはSeriLogを使えばといった既存の仕組みがあるので、そちらを当面使ってほしいとのことのようです。

github.com

確かにサンプルアプリを見るとNLogを使っていて、NLog.config経由でログの設定を行えるので、既存のアプリのconfigをそのまま動かすこともできそうです。将来的には、ビルドインの機能として提供したいようですが、Issueに書いてある通りそこに至るのは時間がかかりそうです。

Logging/samples/SampleApp at 1.0.0-rc1 · aspnet/Logging · GitHub

構造化ログを使いたい場合は...?

GitHubのIssueには上がっています。

github.com

が、これどう見ても検討すらしておらず後回しにしてる様が見て取れます...

実際、ILoggrのメソッド定義を見るに文字列前提にしているため、ここから構造化ログに対応するのは割と骨が折れそうな気配があります。

構造化ログを採用したいなら、Semantic Logging Application Block(SLAB).aspx)を全面的に採用して、EventSource 経由でのロギングにするのがいいのではと思います。SLABはSLABで全く動きがみられないんですが、EventSource自体は.NET標準の機能ですし、そこから取り出す方法は別途考えることができます。この辺のお話はまた別途。

*1:Microsoft.Framework.Logging.がMicrosoft.Extensions.Logging.に変わっている

*2:完全なる推測