NLog 條件式寫入DB

NLog 除了支援 file 寫入之外,也提供了許多 target 的寫入方式,這篇就來介紹客製化寫入 DB 與在某種條件下寫入

對NLog 有興趣的話可以參考前一篇的基本介紹

NLog 支援的寫入DB模版是這樣的, 可以參考官方的寫法

<target xsi:type="Database"
            name="db"
            connectionStringName="LogDBConnection"
            commandText="Layout"
            installConnectionString="Layout">

      <commandText>
        INSERT INTO LogTable(CreateTime,Logger,Message) VALUES(@time_stamp, @logger, @message);
      </commandText>

      <parameter name="@time_stamp" layout="${date}" />
      <parameter name="@logger" layout="${logger}" />
      <parameter name="@message" layout="${message}" />

    </target>

 <target name="file" xsi:type="File"
              fileName="${basedir}/App_Data/Logs/${shortdate}/log.txt"
              layout="${longdate} | ${level:uppercase=true} | ${logger:shortName=true} | ${message} ${newline}" encoding="utf-8"/>

在這邊我們定義了兩個 target,一個是 file, 一個是 db

如果是要採取 file 寫入的方式,將會在自己的本地端新建目錄

如果是要在 db 端寫入的,LogDBConnection記得在 web.config 補上你的 LogDBConnection

而上述的這些參數都是NLog 內建的參數,下面會介紹如果要傳入自定義的參數該怎麼處理

 

在 rule 端,我們可以指定在 namespace 是什麼的情況下,以及最低的層級下,可以寫到多重目標 (寫到 file, db)

更可以設定如果記的內文裡,如果有 test 的字樣的話,action 即設成 ignore,就是不記的意思

官方更是定義了這幾種 action,可以參考這裡

  • Ignore - The message should not be logged.
  • IgnoreFinal - The message should not be logged and processing should be finished.
  • Log - The message should be logged.
  • LogFinal - The message should be logged and processing should be finished.
  • Neutral - The filter doesn't want to decide whether to log or discard the message.
<rules>
    <!-- add your logging rules here -->
    <logger name="TestNameSpace.*" minlevel="Info" writeTo="db, file"  >
      <filters>
        <when condition="contains('${message}', 'test')" action="Ignore" />
      </filters>
    </logger>
  </rules>

在這裡,如果你的 nlog 是在TestNameSpace.* 建立起來的,假若 nlog instance 是在 B.Namespace 建立的,那就不會被記進來。亦或是要記的是全部的話,那就標示為 *

 

客製化欄位寫入 DB

首先先需建立一個 nlog extension

public static class NLogExtension
    {
        public static void LogExt(this NLog.Logger logger, NLog.LogLevel level, String message, String userName)
        {
            NLog.LogEventInfo theEvent = new NLog.LogEventInfo(level, logger.Name, message);
            theEvent.Properties["UserName"] = userName;
            logger.Log(theEvent);
        }
    }

原本 Nlog 的寫法為

_logger.Info("測試訊息");

在使用 Nlog時需改為

_logger.LogExt(LogLevel.Info, "測試訊息", "aceTest");

在 Nlog.config 也需修改為

<target xsi:type="Database"
            name="dbExt"
            connectionStringName="LogDBConnection"
            commandText="Layout"
            installConnectionString="Layout">

      <commandText>
        INSERT INTO LogTable(CreateTime,Logger,Message, UserName) VALUES(@time_stamp, @logger, @message, @UserName);
      </commandText>

      <parameter name="@time_stamp" layout="${date}" />
      <parameter name="@logger" layout="${logger}" />
      <parameter name="@message" layout="${message}" />
      <parameter name="@userName" layout="${event-properties:item=UserName}" />
    </target>

rule端也可以修改為這樣, 同時寫到 db, dbExt, file 這三個地方

<rules>
    <!-- add your logging rules here -->
    <logger name="TestNameSpace.*" minlevel="Info" writeTo="db, dbExt, file"  >
      <filters>
        <when condition="contains('${message}', 'test')" action="Ignore" />
      </filters>
    </logger>
  </rules>

可以讓你任意抽換 target,甚至之後要再加新的欄位

比方說是新增了 MethodName 這個欄位, 想要追蹤是由哪一個 method 發出的話,可以讓 MethodName 允許 null,這樣可以達到尚未上線的程式不會讓現行的 log 機制死掉

而同時上線後也會自動記上相對應的資料,可說是相當方便

 

 

參考文件

https://dotblogs.com.tw/acelee/2018/03/27/120704

https://github.com/NLog/NLog/wiki/Database-target

https://github.com/NLog/NLog/wiki/When-Filter

http://relycoding.blogspot.com/2017/02/nlog.html