C# 使用NLog記錄日誌
引用:https://www.cnblogs.com/felixnet/p/5498759.html
NLog是一個記錄日誌元件,和log4net一樣被廣泛使用,它可以將日誌儲存到文字檔案、CSV、控制檯、VS除錯視窗、資料庫等。最近剛用到這個元件,覺得不錯,水一篇。
下載
通過Nuget安裝NLog,你也可以同時安裝NLog.Config,它會在專案目錄下幫你建立一個配置檔案NLog.config,不過不需要,我們直接手動建立一個,你也可以將配置的資訊寫入到 App.config/Web.config,我比較喜歡獨立出來,不與其它配置摻和在一起。
配置
在專案根目錄下新建一個NLog.config,基本目錄結構:targets下面配置日誌輸出目標及相關引數,rules下面配置目標輸出規則。
1 2 3 4 5 6 7 8 9 10 11 |
<? xml version="1.0" ?>
< nlog >
< targets >
< target ></ target >
< target ></ target >
</ targets >
< rules >
< logger ></ logger >
< logger ></ logger >
</ rules >
</ nlog >
|
記得在NLog.config的屬性中設定 Copy to Output Directory: Copy always
現在我們要將日誌輸出到文字檔案,資料庫,VS除錯視窗,完整配置檔案如下:
<?xml version="1.0" ?> <!--<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" autoReload="true" internalLogLevel="Trace" internalLogFile="D:\work\log.txt">--> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" autoReload="true"> <targets> <!-- Log in a separate thread, possibly queueing up to 5000 messages. When the queue overflows, discard any extra messages--> <!-- write logs to file --> <target name="file" xsi:type="AsyncWrapper" queueLimit="5000" overflowAction="Discard"> <target xsi:type="File" fileName="${basedir}/logs/${shortdate}.log" layout="${longdate} ${level:uppercase=true} ${event-context:item=Action} ${message} ${event-context:item=Amount} ${stacktrace}" /> </target> <!-- write log message to database --> <target name="db" xsi:type="AsyncWrapper" queueLimit="5000" overflowAction="Discard"> <target type="Database" dbProvider="mssql" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=EFinance;Persist Security Info=True;User ID=sa;Password=123456;"> <commandText> INSERT INTO Log(Timestamp,Level,Message,Action,Amount,StackTrace) VALUES(@time_stamp, @level, @message, @action, @amount, @stacktrace); </commandText> <!-- database connection parameters --> <parameter name="@time_stamp" layout="${date}" /> <parameter name="@level" layout="${level:uppercase=true}" /> <parameter name="@message" layout="${message}" /> <parameter name="@action" layout="${event-context:item=Action}" /> <parameter name="@amount" layout="${event-context:item=Amount}" /> <parameter name="@stacktrace" layout="${stacktrace}" /> </target> </target> <!--write log message to Visual Studio Output--> <target name="debugger" xsi:type="Debugger" layout="NLog: ${date:format=HH\:mm\:ss} | ${level:uppercase=true:padding=-5} | ${message}" /> </targets> <rules> <!--TRACE,DEBUG,INFO,WARN,ERROR,FATAL--> <logger name="*" minlevel="Trace" writeTo="debugger" /> <!--INFO,WARN,ERROR,FATAL--> <logger name="*" minlevel="Info" writeTo="db" /> <!--DEBUG,INFO,WARN,ERROR,FATAL--> <logger name="*" minlevel="Debug" writeTo="file" /> </rules> </nlog>
- 如在根節點(nlog)配置 internalLogLevel, internalLogFile,可以檢視NLog輸出日誌時的內部資訊,比如你配置檔案有錯誤,很有幫助,不過專案釋出後還是關閉比較好,以免影響效率;
- 在target外面罩了一個 <target>並且xsi:type為 AsyncWrapper,即表示這條 target 將非同步輸出,這裡我將檔案和資料庫日誌非同步輸出;
- db target內指定了資料庫連線字串 connectionString,SQL語句,SQL引數,還可以指定資料庫/表建立和刪除的指令碼(推薦看NLog原始碼示例,這裡不介紹),同時我們自定義了2個引數 action和amount;
- target引數裡有些是NLog內建引數,比如message,level,date,longdate,exception,stacktrace等,NLog在輸出時會自動賦值;
- layout設定了每條日誌的格式;
- 在rules節點,我們分別指定了三個target輸出日誌的級別,NLog用於輸出日誌的級別包括:Trace,Debug,Info,Warn,Error,Fatal,可以設定 minlevel設定最小級別,也可以用 levels定義你所有需要的級別(多個用逗號分隔)。
封裝
簡單兩句就可以使用NLog了:
NLog.Logger logger = Nlog.LogManager.GetCurrentClassLogger();
logger.Fatal("發生致命錯誤");
logger.Warn("警告資訊");
但是這樣只能記錄了NLog的內建欄位,我們定義的 Amount, Action都不能寫入,接下來我們來封裝一個Logger:
public class Logger { NLog.Logger _logger; private Logger(NLog.Logger logger) { _logger = logger; } public Logger(string name) : this(LogManager.GetLogger(name)) { } public static Logger Default { get; private set; } static Logger() { Default = new Logger(NLog.LogManager.GetCurrentClassLogger()); } #region Debug public void Debug(string msg, params object[] args) { _logger.Debug(msg, args); } public void Debug(string msg, Exception err) { _logger.Debug(err, msg); } #endregion #region Info public void Info(string msg, params object[] args) { _logger.Info(msg, args); } public void Info(string msg, Exception err) { _logger.Info(err, msg); } #endregion #region Warn public void Warn(string msg, params object[] args) { _logger.Warn(msg, args); } public void Warn(string msg, Exception err) { _logger.Warn(err, msg); } #endregion #region Trace public void Trace(string msg, params object[] args) { _logger.Trace(msg, args); } public void Trace(string msg, Exception err) { _logger.Trace(err, msg); } #endregion #region Error public void Error(string msg, params object[] args) { _logger.Error(msg, args); } public void Error(string msg, Exception err) { _logger.Error(err, msg); } #endregion #region Fatal public void Fatal(string msg, params object[] args) { _logger.Fatal(msg, args); } public void Fatal(string msg, Exception err) { _logger.Fatal(err, msg); } #endregion #region Custom public void Process(Models.Log log) { var level = LogLevel.Info; if (log.Level == Models.EFLogLevel.Trace) level = LogLevel.Trace; else if (log.Level == Models.EFLogLevel.Debug) level = LogLevel.Debug; else if (log.Level == Models.EFLogLevel.Info) level = LogLevel.Info; else if (log.Level == Models.EFLogLevel.Warn) level = LogLevel.Warn; else if (log.Level == Models.EFLogLevel.Error) level = LogLevel.Error; else if (log.Level == Models.EFLogLevel.Fatal) level = LogLevel.Fatal; var ei = new MyLogEventInfo(level, _logger.Name, log.Message); ei.TimeStamp = log.Timestamp; ei.Properties["Action"] = log.Action; ei.Properties["Amount"] = log.Amount; _logger.Log(level, ei); } #endregion /// <summary> /// Flush any pending log messages (in case of asynchronous targets). /// </summary> /// <param name="timeoutMilliseconds">Maximum time to allow for the flush. Any messages after that time will be discarded.</param> public void Flush(int? timeoutMilliseconds = null) { if (timeoutMilliseconds != null) NLog.LogManager.Flush(timeoutMilliseconds.Value); NLog.LogManager.Flush(); } } public class MyLogEventInfo : LogEventInfo { public MyLogEventInfo() { } public MyLogEventInfo(LogLevel level, string loggerName, string message) : base(level, loggerName, message) { } public override string ToString() { //Message format //Log Event: Logger='XXX' Level=Info Message='XXX' SequenceID=5 return FormattedMessage; } }
public class Log : IEntityBase<long> { public long Id { get; set; } /// <summary> /// 日誌級別 Trace|Debug|Info|Warn|Error|Fatal /// </summary> public string Level { get; set; } public string Message { get; set; } public string Action { get; set; } public string Amount { get; set; } public string StackTrace { get; set; } public DateTime Timestamp { get; set; } private Log() { } public Log(string level, string message, string action = null, string amount = null) { this.Level = level; this.Message = message; this.Action = action; this.Amount = amount; } }
- Models.Log是我們專案裡的日誌物件,它對應一個數據表Log,NLog將日誌資料寫入到這個表;
- Process(Models.Log)是我們處理自定義物件的日誌方法,用LogEventInfo來寫入;
- 重寫 LogEventInfo.ToString() 是因為 LogEventInfo的Message格式是“Log Event: Logger='XXX' Level=Info Message='XXX' SequenceID=5”,不便於查閱,我們只需要我們設定的Message。
使用:
下面是測試方法,我們一共輸出9條日誌,這9條日誌將輸出到哪個目標,由配置檔案中的Rules/logger決定
Logger.Default.Trace("Hello World! Trace"); Logger.Default.Info("Hello World! Info"); Logger.Default.Warn("Hello World! Warn"); Logger.Default.Debug("Hello World! Debug"); Logger.Default.Error("Hello World! Error"); Logger.Default.Fatal("Hello World! Fatal"); Logger.Default.Process(new Models.Log(Models.EFLogLevel.Info, "Hello World! Info", "TEST", "100.00")); Logger.Default.Process(new Models.Log(Models.EFLogLevel.Debug, "Hello World! Debug", "TEST", "100.00")); Logger.Default.Process(new Models.Log(Models.EFLogLevel.Error, "Hello World! Error", "TEST", "100.00"));
Logger.Default.Flush();
因為我們在Target中設定了非同步,所以如果我們想當場看到輸出結果,就需要使用Flush()方法,實際輸出日誌時就不需要了。
結果:
檢視日誌記錄: