はまったりひらめいたり…とか…

.Net系プログラムで勉強したこととか嵌ったことについて書いたりします。

NLogを.Net Standard/Coreで使用する

はじめに

.Net Core等は下記バージョンでお送りします。

  • netstandard: 2.0
  • netcoreapp: 2.2
  • AspNetCore: 2.2.0
  • NLog: 4.6.3

あらまし

NLogを使うとかは今更ではあるのですが

.Net CoreのExeアプリケーションからASP.net WebAPIアプリケーションで

NLogを使用する機会があったので、学習ついでの備忘録な感じのトピックです。

NLog.configの設定を外に出す

基本的な使い方は本家のGitHubやググったら山程でてくるので割愛…

NLogのログ出力の設定は、nlog.configXML形式ファイルに記述していく感じです。

が、これはいまいち好きじゃない。

と、いうのもASPにしてもCoreの普通のアプリにしてもjsonファイルにアプリケーション設定を記述していますし

あちこちのファイルに設定内容が散らばっているのも少し邪魔くさい。

ASP.netに関してはWebAppsがもっているアプリケーション設定で出力先をいろいろ設定できるようにすれば

CI/CD側の負担も軽くなるんでは?と思ったわけです。

(nlog.configのようなXMLファイルの設定もWebAppsの設定上でできるのであればいいのですが…ない?ですよね?)

NLog.configの構成

まずはXMLで設定されるNLogの構成を見てみます。

<?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="console" xsi:type="Console" />
  </targets>
  <rules>
    <logger name="*" minlevel="Info" writeTo="console" />
  </rules>
</nlog>

これはLogの内容をConsoleに吐き出す設定ですが、target で「何に対して」ログ出力するか指定し

rule で 'target' に対して出力するログの内容を指定しています。

この場合、「Infoレベルからのログを Console に出力する」という設定になっているわけですね。

NLogのTarget/Ruleの関係は、下記サイトが参考になりました。

NLog使い方メモ - マコーの日記

NLogの設定を動的に指定する

こちらのサイトを参考にしました。

NLogをプログラマブルに初期化し動的に構成変更する - M12i.

NLog.Target 名前空間ConsoleTarget というClassが存在します。

NLog/ConsoleTarget.cs at dev · NLog/NLog · GitHub

他にも FileTargetDatabaseTarget が存在します。

Classにあるプロパティを見てみると、LayoutConnectionStringなどXMLで設定するプロパティが存在するのが確認できます。

XMLの設定を確認しながら、TargetClassの同名プロパティに値を設定していく…という方法でNLogの設定ができそうです。

で、出来上がったのが下記です。

public static void ConsoleLogInit()
{
    var conf = LogManager.Configuration;
    var console = new ConsoleTarget("console"); // consoleターゲットを生成
    console.Layout = LogLayout;  // アウトプットフォーマットレイアウトを設定
    conf.AddTarget(console);  // NLogの設定に生成したターゲット情報を追加
    conf.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, console));  // consoleターゲットを使用するルールを追加
    LogManager.Configuration = conf;  // NLogの設定に反映
}

あとは同じように設定するだけ

TargetのClassにたいしてどのようなAPIが存在してどのような引数が求められているのかは

上記のGitHubソースコードドキュメントから抑えることができるので

ファイルに出力する場合やDBに出力する場合も同じように設定していくだけです。

ファイルに出力する場合はファイル名称やエンコードを指定するAPIが追加されていたりします。

public static void WriteLogToFileInit(string filePath, LogLevel targetLogLevel)
{
    var conf = LogManager.Configuration;
    var file = new FileTarget("file");
    file.Encoding = Encoding.UTF8;
    file.FileName = filePath;
    file.Layout = LogLayout;
    conf.AddTarget(file);
    conf.LoggingRules.Add(new LoggingRule("*", targetLogLevel, file));
    LogManager.Configuration = conf;
}

Databaseはちょっと変わり種でDatabaseParameterInfoのインスタンスにLayoutを設定しないといけません。

public static void WriteLogToSqlDatabaseInit(string connectionString, LogLevel targetLogLevel)
{
    var conf = LogManager.Configuration;

    var dbtarget = new DatabaseTarget();
    dbtarget.ConnectionString = connectionString;
    dbtarget.Name = "dbtarget";
    dbtarget.DBProvider = "System.Data.SqlClient";
    dbtarget.CommandText = "Insert Into LoggingTable("
            + "Logged,"
            + ") values ("
            + "@logged,"
            + ")";
    var loggedParam = new DatabaseParameterInfo();
    loggedParam.Name = "@logged";
    loggedParam.Layout = "${date}";
    dbtarget.Parameters.Add(loggedParam);

    conf.AddTarget(dbtarget);
    conf.LoggingRules.Add(new LoggingRule("*", targetLogLevel, dbtarget));
    LogManager.Configuration = conf;
}

外部からNLogの設定を行う!

と、いうわけでソースコード上でNLogの設定が十二分に行えることがわかりました。

あとは、ASP.net WebAPIなどのappsettings.jsonなどに適当な設定を作ってあげればいいだけです。

適当に↓な感じでaapsettings.jsonを作って

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    },
    "OutputToLogFile": {
      "FilePath": "logfile.txt",
      "LogLevel": "Error"
    },
    "OutputToDatabase": {
      "ConnectionString": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=Logging;Integrated Security=True;",
      "LogLevel": "Info"
    }
  },
  "AllowedHosts": "*"
}

Startup.cs あたりで設定ファイルを読み込んでNlogを設定すればいい感じかなと思います。

private void NLogSettings()
{
    Logging.LoggingSettings.ConsoleLogInit();
    var fileName = this.Configuration["Logging:OutputToLogFile:FilePath"];
    var logLevel = this.Configuration["Logging:OutputToLogFile:LogLevel"];
    // NLogの設定を行う~~
}

これでWebAppsのアプリケーション設定への設定のみでログ出力先の挿げ替えなどが簡単に行えるようになりました。

終わりに

今回作成したモロモロのデモは下記リポジトリになります。

ASP.net WebAPIの ActionFilterAttributeExceptionFilterAttribute 使ったり

EntityFrameworkの実行SQLをログ出力したりする実験コードも含んでたりします。

github.com