け日記

SIerから転職したWebアプリエンジニアが最近のIT技術キャッチアップに四苦八苦するブログ

.NET CoreアプリケーションでNLogを使う

.NET Coreアプリケーションでログ出力にはNLogが良いみたいですね。

NLog

NLogは導入が容易で拡張性が高いログ出力ライブラリで、最近ではlog4netよりも人気があるようです。

github.com

.NET Coreの場合は、NLog.Extensions.Loggingを使います。

github.com

NLogのインストール

project.jsonNLog.Extensions.Loggingを記載してインストールします。

{
  "version": "1.0.0-*",
  "dependencies": {
    "Microsoft.Extensions.Configuration": "1.1.0",
    "NLog.Extensions.Logging": "1.0.0-rtm-beta2"
  },
  "frameworks": {
    "netcoreapp1.1": {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.1.0"
        }
      },
      "imports": "dnxcore50"
    }
  }
}

NLog.config

プロジェクトフォルダの直下にNLog.configファイルを作成します。

  • targetsタグ内でログの出力先(ここではfile.txt)を指定します。
  • rulesタグ内で指定のtargetへの出力条件(ここではDebugレベル以上)を記載します。
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <targets>
        <target name="logfile" xsi:type="File" fileName="file.txt" />
    </targets>

    <rules>
        <logger name="*" minlevel="Debug" writeTo="logfile" />
    </rules>
</nlog>

アプリケーション実装

今回はコンソールアプリケーションでログ出力させてみます。
NLog.LogManager#GetCurrentClassLoggerLoggerオブジェクトを取得しています。 引数なしの場合、生成したクラス(ここではProgram)が呼び出し元(caller)のクラスとしてログに出力されます。

using System;
using NLog;

namespace ConsoleApplication
{
    public class Program
    {
        private static Logger _logger = LogManager.GetCurrentClassLogger();

        public static void Main(string[] args)
        {
            _logger.Trace("trace message");
            _logger.Debug("debug message");
            _logger.Info("info message");
            _logger.Warn("warn message");
            _logger.Error("error message");
            _logger.Fatal("fatal message");
        }
    }
}

実行すると、file.txtに以下のように出力されます。
Traceレベルが出力されていないことと、Programが呼び出し元として出力されていることに注意してください。

2017-02-24 21:36:40.1753|DEBUG|Program|debug message
2017-02-24 21:36:40.2848|INFO|Program|info message
2017-02-24 21:36:40.2848|WARN|Program|warn message
2017-02-24 21:36:40.2848|ERROR|Program|error message
2017-02-24 21:36:40.2857|FATAL|Program|fatal message

ログレイアウトをカスタマイズする

NLog.configのtargetsタグではログのレイアウトを細かく設定できます。
例えば↓の感じで設定すると、実行中のクラスとメソッドと行番号まで出力されます。

<targets>
    <target name="logfile" xsi:type="File" fileName="file.txt" 
            layout="${level:uppercase=true:padding=-5} ${longdate} &quot;${message}&quot; ${callsite}#${callsite-linenumber}" />
</targets>
DEBUG 2017-02-24 21:35:09.8425 "debug message" ConsoleApplication.Program.Main#13
INFO  2017-02-24 21:35:10.0356 "info message" ConsoleApplication.Program.Main#14
WARN  2017-02-24 21:35:10.0377 "warn message" ConsoleApplication.Program.Main#15
ERROR 2017-02-24 21:35:10.0391 "error message" ConsoleApplication.Program.Main#16
FATAL 2017-02-24 21:35:10.0421 "fatal message" ConsoleApplication.Program.Main#17

JSONCSVへの出力も全く難しくなく、例えばJSONの場合はlayoutタグでJsonLayoutを指定するだけでOKです。

<targets>
    <target name="logfile" xsi:type="File" fileName="file.txt">
        <layout xsi:type="JsonLayout">
            <attribute name="level" layout="${level}" />
            <attribute name="timestamp" layout="${longdate}" />
            <attribute name="message" layout="${message}" />
            <attribute name="callsite" layout="${callsite}#${callsite-linenumber}" />
        </layout>
    </target>
</targets>
{ "level": "Debug", "timestamp": "2017-02-24 21:27:15.0592", "message": "debug message", "callsite": "ConsoleApplication.Program.Main#13" }

他にもいろいろなレイアウトがあります。
ログの出力クラス(Layout render)は自前で実装することもできます。

ログ出力先を切り替える

例えば、ログレベルがError以上の場合は、通常のログファイルに加えて別のファイルに出力したいといったケースもあるかと思います。
その場合、targetsに通常のログ出力用とErrorログ出力用の2つのtargetを定義して、rulesでログレベルに応じてtargetを切り替えることになります。 下のように設定すると、errorlog.txtにはログレベルがErrorまたはFatalのみが出力されるようになります。

<targets>
    <target name="logfile" xsi:type="File" fileName="log.txt" />
    <target name="errorlogfile" xsi:type="File" fileName="errorlog.txt" />
</targets>
<rules>
    <logger name="*" minlevel="Debug" writeTo="logfile" />
    <logger name="*" minlevel="Error" writeTo="errorlogfile" />
</rules>

出力先にはファイル以外にもメールやDBやコンソールに出力できます。

まとめ

Layout renderやtargetの自前実装について触れませんでしたが、そういった拡張をしなくてもちょっとしたアプリケーションなら十分なログが得られることがわかりました。