這兩天客戶碰到了NLog使用上的問題,程式將Fatal等級的log設定了兩組輸出(File and Windows Event log),但File產出時好時壞,有時那一天應該有log產生但卻整天都沒檔案,來筆記今天白天追蹤NLog無法寫出log的方法。
NLog
NLog是.NET log世界中很受歡迎的Open Source之一,屬於BSD License,一直以來都很想在新專案裡帶上她出門,這次趁幫客戶解問題,來筆記。
NLog本人美照
圖片來源:https://github.com/NLog
Nlog安裝及組態
1.首先新增一個Console專案,並從Nuget分別安裝NLog及NLog.config兩個套件。
Nlog:是Library Project引用寫log時要安裝的,Nlog.config則是Hosting Project要處理config時要安裝的,因為我們這篇的範例只有一個Console專案所以兩個都裝!
2.確認安裝完畢後,接下來我們要先認識組態檔案中的Targets(log目的地)及Rules(Routing條件)
Targets(log目的地)
Target是設定log的目的地,像是flat file、console、window event log、database、msmq、mail等等。(詳細Target可以參考 https://github.com/nlog/NLog/wiki/Targets)
打開NLog.config,她的位置在:
邊我們設定三個Target並加入到上方<targets>元素內,前兩個是log file(type=File),最後一個是event log(Type=EventLog)
<target name="flatfile" xsi:type="File" fileName="C:\temp\log\${shortdate}\debug.log"
layout="${date}| ${level} | ${message}"/>
<target name="fatalfile" xsi:type="File" fileName="C:\temp\log\${shortdate}\fatal.log"
layout="${date}| ${level} | ${message}"/>
<target name="eventlog" xsi:type="EventLog" source="NLogLogger" log="Application"
layout="${date}| ${level} | ${message}"/>
Rules(Routing條件)
Rules是設定那些等級的錯誤要寫到哪一個Target
邊我們設定三個條件並加入上方<rules>元素內。
1.Log等級為Trace、Debug、Info、Warn及Error時對應寫入logfile的target,注意屬性是levels。
2.Log等級為Fatal時,寫入fatalfile的target
3. Log等級為Fatal時,也寫入eventlog的target
<logger name="*" levels="Trace,Debug,Info,Warn,Error" writeTo="logfile" />
<logger name="*" level="Fatal" writeTo="fatalfile" />
<logger name="*" level="Fatal" writeTo="eventlog" />
設定完Targets與Rules後,用簡單的圖來看我們的Logger routing
這次出問題的就是紫爆等級的Fatal小妹。
主機環境設定
這次範例的輸出是檔案及Windows Event log,因此要分別確認log資料夾權限並新增Event Source。
1.建立log資料夾,確認權限。
雖然Nlog會自己建立資料夾,但怕權限上有問題,還是先幫他確認。
2.powershell執行,建立event source NlogLogger
new-eventlog -Source NLogLogger -LogName Application
NLog元件在C#程式中的引用方式
在console專案下的program.cs輸入程式碼
using NLog;
class Program
{
private static Logger logger = LogManager.GetCurrentClassLogger();
static void Main(string[] args)
{
logger.Trace("我是追蹤:Trace");
logger.Debug("我是偵錯:Debug");
logger.Info("我是資訊:Info");
logger.Warn("我是警告:Warn");
logger.Error("我是錯誤:error");
logger.Fatal("我是致命錯誤:Fatal");
}
}
如果要把Exception物件輸出,也可以放在第一個引數,第二個引數可以接其他訊息。
執行程式結果:
Log file
debug.log內容
fatal.log內容
Windows Event log
Windows鍵 + R 輸入 eventvwr.msc 打開事件檢視器
Windows記錄 > 應用程式 > 來源=NLogLogger > 內容
在本機或是測試環境總是順順利利的!
追蹤Nlog問題
但有時候我們可能會在正式上版後遇到NLog無法寫出log file或是寫到Windows Event log失敗的問題,但NLog內部執行時若遇到錯誤,避免影響主程式執行,NLog預設會先略過!
好在NLog有troubleshooting的步驟可以參考,這邊我們先用檔案追蹤:
在NLog.Config檔案中的element內設定以下
<nlog ... internalLogLevel="Error" internalLogFile="c:\temp\log\nlog-internal.log">
...
</nlog>
(也可以output to console)
接下來去收internal log就可以知道Log檔案寫入失敗的原因了!
這邊我們會刻意關閉資料夾權限並且設定錯誤的event source來測試,執行完Console程式後,打開nlog-internal.log
檔案內容:
- 找不到來源,但無法搜尋部分或全部的事件紀錄檔。無法存取的紀錄檔:Security: 用powershell新增event source。
- 存取被拒: 確認資料夾是否有權限寫入
最後如果連internal log也失效,還有另外一招throwExceptions="true",讓錯誤回拋到主程式處理。
<nlog throwExceptions="true">
...
</nlog>
小結:
- NLog 也丟到 Slack 吧! 如果想把NLog產出的log拋到slack,推薦Demo大的這篇
- 如果想把NLog產出的log拋到Database,推薦mrkt大這篇使用NLog - Advanced .NET Logging (2)!
參考:
Will 保哥 .Net, ASP.NET, 介紹好用工具NLog
NLog - Advanced .NET Logging (2)