NLogでログをとる

やりたいこと

以前、自前でログを取るためのクラスを作ったりしたが、マルチスレッドの場合に同時に書き込んだりすると落ちるなど、問題があった。
頑張って自分で作るのもいいが、世の中には便利なログ取りライブラリがある様子。

最近NLogというのに触れる機会があったので、それの使い方をちょっと調べてみる。

やったこと

ログを取りたいプロジェクトに、NLogをnugetでインストールする。2022/10月時点の最新は5.0.4。

前提

  • VisualStudion2022 v17.3.0
  • C#
  • NLog v5.0.4

設定をする(NLog.configを書いて配置)

まずは、NLogのチュートリアルを見ながら、NLogの設定をする。
設定は、コードからも、コンフィグファイル(NLog.config)でも行える。

Nlog.configという名前のファイルをPJに追加して、「ローカルにコピー」にしておけば、勝手にexeの横にコピーされて、その設定で動いてくれる。

設定は、コードからもできる様子だが、今回はやらない。

ターゲットの指定(ログを何に出力するか)

ターゲットは複数指定できる。

ターゲットには、ログファイルのほかにConsole出力なんかもある。
(ほかにもいろいろあるようだが、今回は試さない)
https://nlog-project.org/config/?tab=targets
→メールとかもできるっぽい。

複数指定すると、ログファイルとconsole表示の両方に出力する、なんかもできる。

ログの中身をつくる(Layoutを書く)

ログの中身は<target >の中のlayoutをいじることでカスタムできる。 基本は下記になっているらしい。

<target name="logfile" xsi:type="File" fileName="file.txt" layout="`${longdate}|${level:uppercase=true}|${logger}|${message:withexception=true}`" />

どんな項目を出せるか=layoutにどういう値をセットできるか、を下記を見ながらいろいろやる。

https://nlog-project.org/config/?tab=layout-renderers

csvっぽいログにしたいときは、下記のように、layoutxsi:typeCsvLayoutにして、 columnに出力したい内容をセットしていく。

参考:https://github.com/NLog/NLog/wiki/CsvLayout

<?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 xsi:type="File" name="csvFileExample" fileName="./CsvLogExample.csv">
            <layout xsi:type="CsvLayout" delimiter="Enum" withHeader="false">
                <column name="time" layout="${longdate}" />
                <column name="level" layout="${level:upperCase=true}"/>
                <column name="message" layout="${message}" />
                <column name="callsite" layout="${callsite:includeSourcePath=true}" />
                <column name="stacktrace" layout="${stacktrace:topFrames=10}" />
                <column name="exception" layout="${exception:format=ToString}"/>
                <column name="property1" layout="${event-properties:property1}"/>
            </layout>
        </target>
        <target name="logfile" xsi:type="File" fileName="ConfigByNlogConfig.log" />
        <target name="logconsole" xsi:type="Console" />
    </targets>

    <rules>
        <logger name="*" minlevel="Info" writeTo="logconsole" />
        <logger name="*" minlevel="Debug" writeTo="logfile" />
        <logger name="*" minlevel="Info" writeTo="csvFileExample" />
    </rules>
</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 xsi:type="File" name="csvFileExample" fileName="./CsvLogExample.csv">
            <layout xsi:type="CsvLayout" delimiter="Enum" withHeader="false">
                <column name="time" layout="${longdate}" />
                <column name="level" layout="${level:upperCase=true}"/>
                <column name="message" layout="${message}" />
                <column name="callsite" layout="${callsite:includeSourcePath=true}" />
                <column name="stacktrace" layout="${stacktrace:topFrames=10}" />
                <column name="exception" layout="${exception:format=ToString}"/>
                <column name="property1" layout="${event-properties:property1}"/>
            </layout>
        </target>
    </targets>

    <rules>
        <logger name="*" minlevel="Info" writeTo="csvFileExample" />
    </rules>
</nlog>
using NLog;

namespace NlogJikken
{
    internal class Program
    {
        private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();

        static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");
            
            //var config = new NLog.Config.LoggingConfiguration();

            //var logfile = new NLog.Targets.FileTarget() { FileName = "ConfigByCode.log" };
            //var logconsole = new NLog.Targets.ConsoleTarget();

            //config.AddRule(LogLevel.Info, LogLevel.Fatal, logconsole);
            //config.AddRule(LogLevel.Debug, LogLevel.Fatal, logfile);

            ////NLog.LogManager.Configuration = config;

            Task.Run(()=>
            {
                for (int i = 0; i < 50; i++)
                {
                    Logger.Info(i);
                }
            });

            Task.Run(() =>
            {
                for (int i = 0; i < 50; i++)
                {
                    Logger.Info(i);
                }
            });

            Console.ReadLine();
        }
    }
}

参考

NLog nuget

https://www.nuget.org/packages/NLog/

NLogリポジトリのTutorial

https://github.com/nlog/nlog/wiki

https://github.com/nlog/nlog/wiki/Tutorial

NLog.configを探す場所のルール

https://github.com/nlog/nlog/wiki/Configuration-file#file-locations

ログのターゲット(何に出力するのか、fileなのか、Consoleなのか)

https://nlog-project.org/config/?tab=targets

レイアウト(標準(特に書式なしの横にツラツラ書くヤツ)なのが、csvなのか、jsonなのか)の指定の書き方

https://nlog-project.org/config/?tab=layouts

csvのレイアウトの例

https://github.com/NLog/NLog/wiki/CsvLayout

ログの中身のカスタム(さわりの部分)

https://github.com/nlog/nlog/wiki/Tutorial#layouts-and-layoutrenderers

ログの中身のカスタム(具体的にどう書けばいいか)

https://nlog-project.org/config/?tab=layout-renderers

参考書

WinUI3

WinUI3でアプリを作ろうと思ったときのとっかかりによかった。 msdocsに書いてある情報を、体系的に、順番に読みたいな、というときによいかも。(ただし英語)
この本で分からなかった、かゆいところに手が届かなかった部分を私は記事にしてる感じ。

C#①

表紙に書いてある通り、教科書として最適。 これからC#を勉強したいけど、ネットだけで勉強するのは効率が悪いから体系的に学べる本が欲しいときや、 ちょっとC#を勉強してコード書けるようになったけど、もう少し広く深く知りたいなというときによいと思う。
私は仕事で触れるコードを軸に、基本ネットで断片的にC#を学んだので、その知識の隙間を埋めて枝葉を広げるためにとても分かりやすかった。

C#②

C#の文法的に色々できるのは分かったが、いざ実装するときに、わかったことを使ってどう実装すればいいのか?と悩んだときに指針になりそうな本。
「プロパティ等の名前の付け方、どうすればいい?」「情報をクラス外部に見せるときに、プロパティにすべき?メソッドにすべき?」「異常だと判定したいとき、どんなときにどんな例外をスローすべき?」などなど、勉強になる部分が山ほどあった。
私のように「コードは書くけどこれであってるのか自信がない、レビューで指摘されるのが嫌だ、実装時の(心の)よりどころが欲しい」という人に最適。