前言
日志是每個程序的基本模塊。本文是為了探究如何通過NLog方便及記錄日志並通過Log4View工具收集日志統一查看。
為什么是NLog?
下載量NLog和Log4Net差不多,這兩個日志模塊是.Net平台使用最多的兩大日志模塊。

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

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

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" />


目標
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可以異步保存日志,從而防止日志影響業務性能。
-
xsi:type:輸入類型,支持以下類型。- ColoredConsole : 使用可自定義的顏色將日志消息寫入控制台。
- Console - 將日志消息寫入控制台。
- Debug - 模擬目標-用於測試。
- File - 將日志消息寫入一個或多個文件。
- Mail - 使用 smtp 協議或拾取文件夾通過電子郵件發送日志郵件。
- Null - 丟棄日志消息。主要用於調試和基准測試。
-
name:目標的名字,可以通過創建Rule規則限制目標的輸出。 -
fileName:文件名,日志保存文件時可以保存到該文件中。文件名支持參數化,通過各種參數更方便的輸出日志。 -
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>
xsi:type:將文件類型設置為File,將日志保存到文件中。fileName:將日志文件保存到"${logDir}/InfoLogs/log.txt"。可以通過參數在文件名中加入參數設置。
archiveFileName:為了防止日志文件保存的太大,我們將日志文件拆分保存。通過archiveFileName參數設置保存格式,具體格式可以到這里查看。createDirs:若設置的日志文件夾不存在,則自動創建文件夾。keepFileOpen:為了提高文件寫入性能,避免每次寫入文件都開關文件,將keepFileOpen設置為true,我們通過openFileCacheTimeout參數定時關閉文件。autoFlush:為了提高日志寫入性能,不必每次寫入日志都直接寫入到硬盤上,將autoFlush設置為false,我們通過openFileFlushTimeout參數定時寫入文件。openFileCacheTimeout:將keepFileOpen參數設置為false,則設置定時關閉日志。防止日志一直開着占用着。openFileFlushTimeout:將autoFlush參數設置為false,則設置定時將日志從緩存寫入到硬盤時間。archiveAboveSize:為了防止一個文件日志太大,我們需要根據指定大小將日志拆文件保存。archiveAboveSize參數的單位是字節。通過設置為10240=10KB,每個日志大小達到10KB就會自動拆分文件,拆分后的文件名規則通過archiveFileName設置,拆分文件名的規則通過archiveNumbering設置,具體規則可以查看這里。concurrentWrites:支持多個並發一起寫文件,提高文件寫入性能。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>

參數
在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支持多種目標的文件輸入,可以通過文件,數據庫或網絡等途徑輸入日志。
打開后界面如圖所示

在File-Receiver添加一個接收者




通過以上設置即可在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);
}

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

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


結語
本文對Nlog的簡單使用進行了探究,通過配置的方式將文件異步保存到本地和通過udp的方式發送到Log4View2進行更方便的查看,同時Nlog也支持通過代碼的方式進行控制,但是使用配置修改相比代碼更為靈活,因此本文對代碼修改配置的方式不做探討。
參考文檔
- 框架學習與探究之日志組件--Log4Net與NLog
- NLog基本介紹
- 一個簡單好用的日志框架NLog
- .Net日志庫Nlog的詳細配置與調用演示
- NLog tutorial
- Advanced NLog Configuration file
- Log4ViewHelp
微信掃一掃二維碼關注訂閱號傑哥技術分享
本文地址:https://www.cnblogs.com/Jack-Blog/p/10117218.html
作者博客:傑哥很忙
歡迎轉載,請在明顯位置給出出處及鏈接

