NLog日志框架使用探究-1




前言

日志是每個程序的基本模塊。本文是為了探究如何通過NLog方便及記錄日志並通過Log4View工具收集日志統一查看。

為什么是NLog?

下載量NLog和Log4Net差不多,這兩個日志模塊是.Net平台使用最多的兩大日志模塊。
3.png

Log4Net上次更新已經是17年3月
1.png

NLog更新的比較頻繁,開發者比較活躍,有問題的話修復更及時。
2.png

NLog是適用於各種.net平台(包括.net standard)的靈活而免費的日志記錄平台。通過NLog, 可以輕松地寫入多個目標。(數據庫、文件、控制台), 並動態更改日志記錄配置。
NLog支持結構化和傳統日志記錄。NLog的特點: 高性能、易於使用、易於擴展和靈活配置。

目的

本文為了探究NLog的使用方式,以及如何通過NLog將日志統一收集查看並管理。

配置

NLog可以通過配置方式輕松的記錄不同等級,不同結構的日志。
通過Nuget獲取NLog庫包
Install-Package NLog -Version 4.5.11
下載完后會自動在程序下加入默認的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"
      xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
      autoReload="true"
      throwExceptions="false"
      internalLogLevel="Info"
	  internalLogFile="./logs/nlog-internal.log">

  <!-- optional, add some variables
  https://github.com/nlog/NLog/wiki/Configuration-file#variables
  -->
  <!--
  See https://github.com/nlog/nlog/wiki/Configuration-file
  for information on customizing logging rules and outputs.
   -->
  <targets>

    <!--
    add your targets here
    See https://github.com/nlog/NLog/wiki/Targets for possible targets.
    See https://github.com/nlog/NLog/wiki/Layout-Renderers for the possible layout renderers.
    -->

    <!--
    Write events to a file with the date in the filename.
    <target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
            layout="${longdate} ${uppercase:${level}} ${message}" />
    -->
	</targets>
  <rules>
    <!-- add your logging rules here -->

    <!--
    Write all events with minimal level of Debug (So Debug, Info, Warn, Error and Fatal, but not Trace)  to "f"
    <logger name="*" minlevel="Debug" writeTo="f" />
    -->
  </rules>
</nlog>

Nlog支持多種配置方式,具體其他配置方式看下《一個簡單好用的日志框架NLog》,講解的很詳細。

基本配置

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
      autoReload="true"
      throwExceptions="false"
      internalLogLevel="Info"
	  internalLogFile="./logs/nlog-internal.log">

NLog 根節點以下幾種配置需要注意

  • autoReload:配置修改是否自動加載。
  • throwExceptions:日志出現異常時是否需要拋出異常,若配置為true日志記錄異常時由於沒有捕獲異常,會導致程序掛掉。
  • internalLogLevel:表示nlog日志的執行日志記錄等級。
  • internalLogFile:表示nlog日志的執行日志記錄的位置。通過./XXXX的方式可以配置到程序的相對目錄。

日志等級

Nlog支持以下幾種日志等級

Level FirstCharacter Ordinal
Trace T 0
Debug D 1
Info I 2
Warn W 3
Error E 4
Fatal F 5
Off O 6

在日志輸入時可以通過${level}輸入日志等級,或者通過${level:format=FirstCharacter}輸出日志等級的簡寫。
若想查看所有參數輸出可以到這里查看。

輸出例子

Logger logger = NLog.LogManager.GetLogger("test");
logger.Trace("測試test");
logger.Info("測試test");
logger.Warn("測試test");
logger.Error("測試test");
logger.Fatal("測試test");

通過NLog.LogManager.GetLogger我們可以獲取一個日志對象示例。傳入的參數為日志實例名,我們可以在日志名中通過${logger}參數輸出日志實例名。可以將不同的日志保存到不同的文件。

在代碼中我們不支持Off等級的輸出。通過NLog不需要我們認為對日志模塊進行啟動或關閉,在我們程序關閉后,它會自動關閉日志。相關的Nlog的日志可以在internalLogFile配置的路徑中中查看到,同時在生產環境建議將internalLogLevelNLog自己的日志等級設置為Info,這樣只會記錄關鍵的日志信息。

我們輸入到文件中,輸入配置如下:

<target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
            layout="${longdate} ${uppercase:${level}} ${message}" />
<logger name="*" minlevel="Debug" writeTo="f" />

4.png

5.png

目標

NLog通過target配置日志輸入的目標。可以通過配置多個target將日志輸入到多個目錄,多個目標(文件,網絡,數據庫等)。

<targets async="true">
  <target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
            layout="${longdate} ${uppercase:${level}} ${message}" />
</targets>

通過將async設置為true可以異步保存日志,從而防止日志影響業務性能。

  1. xsi:type:輸入類型,支持以下類型。

    • ColoredConsole : 使用可自定義的顏色將日志消息寫入控制台。
    • Console - 將日志消息寫入控制台。
    • Debug - 模擬目標-用於測試。
    • File - 將日志消息寫入一個或多個文件。
    • Mail - 使用 smtp 協議或拾取文件夾通過電子郵件發送日志郵件。
    • Null - 丟棄日志消息。主要用於調試和基准測試。
  2. name:目標的名字,可以通過創建Rule規則限制目標的輸出。

  3. fileName:文件名,日志保存文件時可以保存到該文件中。文件名支持參數化,通過各種參數更方便的輸出日志。

  4. layout:表示輸出的格式,若為最簡單的內容輸入,則直接通過參數設置輸入格式即可。除了最簡單的文本格式還支持以下四種類型的數據,通過xsi:type參數設置layout的格式,如xsi:type="JsonLayout"

    • CSV - A specialized layout that renders CSV-formatted events.
    • Compound - A layout containing one or more nested layouts.
    • JSON - A specialized layout that renders to JSON.
    • Log4JXml - A specialized layout that renders Log4j-compatible XML events.

下面列舉兩項常用的輸入方式,文件輸出和網絡輸出。

文件輸出

通過文件輸入將日志保存到一個或多個文件。可以通過配置動態進行日志的保存。

下面通過json 的格式保存日志信息。

<?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" xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd" autoReload="true" throwExceptions="false" internalLogLevel="Info" internalLogFile="./logs/nlog-internal.log">
    <targets>
        <target xsi:type="File" name="InfoFile" 
        fileName="${logDir}/InfoLogs/log.txt" 
        archiveFileName="${logDir}/InfoLogs/log.{#}.txt" 
        createDirs="true" keepFileOpen="true" autoFlush="false" 
        openFileFlushTimeout="10" openFileCacheTimeout="30" archiveAboveSize="10240" 
        archiveNumbering="Sequence" concurrentWrites="true" encoding="UTF-8">
            <layout xsi:type="JsonLayout">
                <attribute name="counter" layout="${counter}" />
                <attribute name="time" layout="${longdate}" />
                <attribute name="level" layout="${level:upperCase=true}"/>
                <attribute name="message" layout="${message:format=message}" encode="false" />
            </layout>
        </target>
    </targets>
    <rules>
        <logger name="*" minlevel="Info" writeTo="InfoFile" />
    </rules>
</nlog>
  1. xsi:type:將文件類型設置為File,將日志保存到文件中。
  2. fileName:將日志文件保存到"${logDir}/InfoLogs/log.txt"

    可以通過參數在文件名中加入參數設置

  3. archiveFileName:為了防止日志文件保存的太大,我們將日志文件拆分保存。通過archiveFileName參數設置保存格式,具體格式可以到這里查看。
  4. createDirs:若設置的日志文件夾不存在,則自動創建文件夾。
  5. keepFileOpen:為了提高文件寫入性能,避免每次寫入文件都開關文件,將keepFileOpen設置為true,我們通過openFileCacheTimeout參數定時關閉文件。
  6. autoFlush:為了提高日志寫入性能,不必每次寫入日志都直接寫入到硬盤上,將autoFlush設置為false,我們通過openFileFlushTimeout參數定時寫入文件。
  7. openFileCacheTimeout:將keepFileOpen參數設置為false,則設置定時關閉日志。防止日志一直開着占用着。
  8. openFileFlushTimeout:將autoFlush參數設置為false,則設置定時將日志從緩存寫入到硬盤時間。
  9. archiveAboveSize:為了防止一個文件日志太大,我們需要根據指定大小將日志拆文件保存。archiveAboveSize參數的單位是字節。通過設置為10240=10KB,每個日志大小達到10KB就會自動拆分文件,拆分后的文件名規則通過archiveFileName設置,拆分文件名的規則通過archiveNumbering設置,具體規則可以查看這里
  10. concurrentWrites:支持多個並發一起寫文件,提高文件寫入性能。
  11. encoding: Nlog默認保存的編碼格式為Encoding.Default,中文保存到日志中會出現亂碼,將其設置為utf-8,就可以正常保存了。

我們可以在targets節點下增加多個target,用於輸出多中目標。

當我們開啟異步記錄日志時,同時設置了保持文件打開,且設置了緩存時間,若在時間內超過了日志大小,並不會立即分文件,而是在文件關閉后才會進行分文件。

Json格式保存

<layout xsi:type="JsonLayout">
    <attribute name="counter" layout="${counter}" />
    <attribute name="time" layout="${longdate}" />
    <attribute name="level" layout="${level:upperCase=true}"/>
    <attribute name="message" layout="${message:format=message}" encode="false" />

在target中將layout的 xsi:type設置為JsonLayout保存為Json格式。
Json格式保存我們需要在layout節點下增加attribute來增加字段。上面增加了四個字段。

  • counter:行數,行數表示日志當前記錄的行數。
  • time:時間,可以通過參數保存自己想要的時間格式。
  • level:日志等級,當前記錄的日志等級。
  • message:信息,記錄的信息,若需要記錄中文,則需要設置`encode="false",否則json格式會自動將json的中文內容保存為unicode編碼。

具體的其他Json參數可以看這里

多目標

<targets>
    <target xsi:type="File" name="InfoFile" fileName="${logDir}/InfoLogs/log.txt" archiveFileName="${logDir}/InfoLogs/log.{#}.txt" createDirs="true" keepFileOpen="true" autoFlush="false" 
    openFileFlushTimeout="10" openFileCacheTimeout="30" 
    archiveAboveSize="10240" archiveNumbering="Sequence" concurrentWrites="true" encoding="UTF-8">
        <layout xsi:type="JsonLayout">
            <attribute name="counter" layout="${counter}" />
            <attribute name="time" layout="${longdate}" />
            <attribute name="level" layout="${level:upperCase=true}"/>
            <attribute name="message" layout="${message:format=message}" encode="false" />
        </layout>
    </target>
    <target xsi:type="File" name="ErrorFile" fileName="${logDir}/ErrorLogs/log.txt" 
    archiveFileName="${logDir}/ErrorLogs/log.{#}.txt" createDirs="true" keepFileOpen="true" autoFlush="false" 
    openFileFlushTimeout="10" openFileCacheTimeout="30" 
    archiveAboveSize="10240" archiveNumbering="Sequence" 
    concurrentWrites="true" encoding="UTF-8">
        <layout xsi:type="JsonLayout">
            <attribute name="time" layout="${longdate}" />
            <attribute name="level" layout="${level:upperCase=true}"/>
            <attribute name="message" layout="${message}" encode="false" />
            <attribute name="exception">
                <layout xsi:type="JsonLayout">
                    <attribute name="callsite" layout="${callsite}" />
                    <attribute name="callsite-linenumber" layout="${callsite-linenumber} " />
                </layout>
            </attribute>
        </layout>
    </target>
</targets>

<rules>
    <logger name="*" minlevel="Info" writeTo="InfoFile" />
    <logger name="*" minlevel="Error" writeTo="ErrorFile" />
</rules>

我們可以在<targets>節點下增加多個target增加多個輸出目標,我們通過設置2個目標,將info和error日志分開保存。其中很多參數是共用的,我們可以設置一個默認參數default-target-parameters,減少配置文件節點。

<default-target-parameters xsi:type="File" 
                createDirs="true" 
                keepFileOpen="true" autoFlush="false" openFileFlushTimeout="10" openFileCacheTimeout="30"
                archiveAboveSize="10240" archiveNumbering="Sequence" concurrentWrites="true" encoding="UTF-8"/>

通過以上設置,這些設計的節點就被設置為默認值,簡化后的配置文件如下。

<target>

    <default-target-parameters xsi:type="File" createDirs="true" keepFileOpen="true" autoFlush="false" openFileFlushTimeout="10" openFileCacheTimeout="30" archiveAboveSize="10240" archiveNumbering="Sequence" concurrentWrites="true" encoding="UTF-8"/>
    <target xsi:type="File" name="InfoFile" fileName="${logDir}/InfoLogs/log.txt" archiveFileName="${logDir}/InfoLogs/log.{#}.txt">
        <layout xsi:type="JsonLayout">
            <attribute name="counter" layout="${counter}" />
            <attribute name="time" layout="${longdate}" />
            <attribute name="level" layout="${level:upperCase=true}"/>
            <attribute name="message" layout="${message:format=message}" encode="false" />
        </layout>
    </target>
    <target xsi:type="File" name="ErrorFile" fileName="${logDir}/ErrorLogs/log.txt" archiveFileName="${logDir}/ErrorLogs/log.{#}.txt">
        <layout xsi:type="JsonLayout">
            <attribute name="time" layout="${longdate}" />
            <attribute name="level" layout="${level:upperCase=true}"/>
            <attribute name="message" layout="${message}" encode="false" />
            <attribute name="exception">
                <layout xsi:type="JsonLayout">
                    <attribute name="callsite" layout="${callsite}" />
                    <attribute name="callsite-linenumber" layout="${callsite-linenumber} " />
                </layout>
            </attribute>
        </layout>
    </target>
</targets>

<rules>
    <logger name="*" minlevel="Info" writeTo="InfoFile" />
    <logger name="*" minlevel="Error" writeTo="ErrorFile" />
</rules>

16.png

參數

在Nlog節點下加入variable節點可以創建自定義參數。

  <variable name="logDir" value="${basedir}/logs/${logger:shortName=true} /${shortdate}"/>
  • name:表示參數名。
  • value:表示參數值。

參數設置完后就可以通過${name}的方式獲取參數值。
Nlog已定義的一些參數可以到查看

規則

通過target我們可以自定義輸出方式。同時我們可以創建一系列規則約束輸出的內容。

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

Nlog節點下添加rules節點,rules節點下可以配置多個logger節點,每個logger節點即為一條約束。

  • name:logger名稱,若為*則表示適用於所有日志,若我們某個target專門用於logdemo.test類的日志輸出,則那么可以設置為logdemo.test.*,表示當前約束只允許命名空間為logdemo.test開頭的日志輸出。
  • minlevel:表示當前約束的最小等級,只有等於或大於該值的日志等級才會被記錄。
  • writeTo:表示當前規則約束哪個target

更多其他規則參數可以看這里

日志分發

通過以上設置,我們可以通過各種targets將日志存放到不同地方,通過rules指定保存不同等級的日志。日志本地文件存放主要是用於進行系統排查錯誤用的,有時候我們可能希望將日志合並存放或查看。NLog本身就支持通過Tcp或Udp將日志分發到其他地方。

我們在保存文件的同時只需要添加一條target,同時將其類型設置為Network,在通過設置rules對其進行必要約束就可以將日志分發到其他地方。由於我們前面設置了async參數異步保存日志,因此網絡好壞並不會影響我們業務處理時效。

<?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" xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd" autoReload="true" throwExceptions="false" internalLogLevel="Info" internalLogFile="./logs/nlog-internal.log">
    ...
    <targets async="true">

    ...
    </targets>

    <targets async="true">
        <target xsi:type="Network" address="udp://127.0.0.1:878" name="network" newLine="false" maxMessageSize="65000" encoding="gbk" layout="${log4jxmlevent:includeCallSite=true:includeNLogData=true}"/>
    </targets>

    <rules>
        <logger name="*" minlevel="Info" writeTo="network" />
        ...
    </rules>
</nlog>

為了和文件區分,我們我們新增了一個targets專門用於Network。

  • xsi:type:通過設置類型為Network表示通過網絡傳輸日志。
  • address:設置地址格式為協議://ip:端口
  • maxMessageSize:表示最大傳輸消息大小,默認為65000。
  • newLine:表示日志消息末尾追加換行符。
  • encoding:表示日志傳輸的編碼,默認為UTF-8,中文需要設置為GBK編碼,否則在對端可能會出現亂碼的情況。

具體完整參數可以看這里

通過以上設置,就可以將日志發送到指定地址了,通過Log4JXml格式發送到對端。

日志收集

我們通過Log4View收集日志進行查看。目前官網最新的是Log4View2版本,有30天的免費使用時間,30天自動變為社區版本,依然可以免費使用,但是想使用一些高級功能則需要付費使用。

Log4View支持Nlog和Log4Net,同時支持查找,過濾等功能。
從官網下載后需要進行安裝,目前Log4View不支持中文。

Log4View2支持多種目標的文件輸入,可以通過文件,數據庫或網絡等途徑輸入日志。

打開后界面如圖所示
6.png

在File-Receiver添加一個接收者
7.png

8.png

9.png

10.png

通過以上設置即可在Log4View接收數據了。我們發送幾條消息

Logger logger = NLog.LogManager.GetLogger("test");

logger.Trace("測試test");
logger.Info("測試test");
logger.Warn("測試test");
logger.Error("測試test");
logger.Fatal("測試test");
try
{
    throw new Exception("錯誤test");
}
catch (Exception exception)
{
    logger.Error(exception);
}

11.png

由於我們設置的日志等級為Info,因此Trace等級的日志不會傳輸過來。
12.png

在界面左下角可以添加過濾器,支持多種篩選模式。

13.png
15.png

結語

本文對Nlog的簡單使用進行了探究,通過配置的方式將文件異步保存到本地和通過udp的方式發送到Log4View2進行更方便的查看,同時Nlog也支持通過代碼的方式進行控制,但是使用配置修改相比代碼更為靈活,因此本文對代碼修改配置的方式不做探討。


參考文檔

  1. 框架學習與探究之日志組件--Log4Net與NLog
  2. NLog基本介紹
  3. 一個簡單好用的日志框架NLog
  4. .Net日志庫Nlog的詳細配置與調用演示
  5. NLog tutorial
  6. Advanced NLog Configuration file
  7. Log4ViewHelp

20191127212134.png
微信掃一掃二維碼關注訂閱號傑哥技術分享
本文地址:https://www.cnblogs.com/Jack-Blog/p/10117218.html
作者博客:傑哥很忙
歡迎轉載,請在明顯位置給出出處及鏈接


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM