在.NET Core框架中使用NLog組件記錄日誌,寫資料庫,寫文件!!! ...
接觸.net項目的同志們都清楚,最初在項目中記錄日誌常用的是log4net日誌組件,隨著.net框架的不對優化升級,最近新流行的日誌框架nlog,下麵我就對nlog組件說說自己的認知:
下載
通過Nuget安裝NLog
配置
在項目根目錄下新建一個NLog.config(在Nuget包中也可以下載NLog.config包,下載預設的位置是C盤,可能和你的工程不在同一個文件夾,不建議使用),基本目錄結構:targets下麵配置日誌輸出目標及相關參數,rules下麵配置目標輸出規則:
1 <?xml version="1.0" ?> 2 <nlog> 3 <targets> 4 <target></target> 5 <target></target> 6 </targets> 7 <rules> 8 <logger></logger> 9 <logger></logger> 10 </rules> 11 </nlog>NLog.config
記得在NLog.config的屬性中設置 Copy to Output Directory: Copy always,作用是每次重新生成解決方案的時候都會將改配置文件複製的本地目錄,否則本地找不到配置文件無法將日誌記錄到文件中:
完整的配置文件如下,日誌配置文件儘量單獨創建一個文件:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 3 <targets> 4 <!--寫入文件--> 5 <target xsi:type="File" name="DebugFile" fileName="Logs\Debug\${shortdate}.log" 6 layout="日誌時間:${longdate}${newline}日誌來源:${callsite}${newline}日誌級別:${uppercase:${level}}${newline}消息內容:${message}${newline}異常信息:${exception}${newline}==============================================================${newline}" > 7 </target> 8 <target xsi:type="File" name="InfoFile" fileName="Logs\Info\${shortdate}.log" 9 layout="日誌時間:${longdate}${newline}日誌來源:${callsite}${newline}日誌級別:${uppercase:${level}}${newline}消息內容:${message}${newline}異常信息:${exception}${newline}==============================================================${newline}" > 10 </target> 11 <target xsi:type="File" name="ErrorFile" fileName="Logs\Error\${shortdate}.log" 12 layout="日誌時間:${longdate}${newline}日誌來源:${callsite}${newline}日誌級別:${uppercase:${level}}${newline}消息內容:${message}${newline}異常信息:${exception}${newline}==============================================================${newline}" > 13 </target> 14 15 <target xsi:type="Database" name="NewDatabase" > 16 <dbProvider>System.Data.SqlClient</dbProvider> 17 <connectionString> 18 Data Source=127.0.0.1;Initial Catalog=FlightAnalysis;Persist Security Info=true;User ID=sa;Password=111111; 19 </connectionString> 20 <commandText> 21 insert into OperatorLog(Id,AppName,ModuleName,ProcName,OperationType,Logger,LogMessage,IP,UserName,LogLevel) 22 <!--values(@Id,'','','',0,'','','','','',getdate())--> 23 values(@Id,@AppName,@ModuleName,@ProcName,@OperationType,@Logger,@LogMessage,@IP,@UserName,@LogLevel) 24 </commandText> 25 <parameter name="@Id" layout="${event-context:item=Id}" /> 26 <parameter name="@AppName" layout="${event-context:item=AppName}" /> 27 <parameter name="@ModuleName" layout="${event-context:item=ModuleName}" /> 28 <parameter name="@ProcName" layout="${event-context:item=ProcName}" /> 29 <parameter name="@OperationType" layout="${event-context:item=OperationType}" /> 30 <parameter name="@Logger" layout="${event-context:item=Logger}" /> 31 <parameter name="@LogMessage" layout="${event-context:item=LogMessage}" /> 32 <parameter name="@IP" layout="${event-context:item=IP}" /> 33 <parameter name="@Longdate" layout="${event-context:item=Longdate}" /> 34 <parameter name="@UserName" layout="${event-context:item=UserName}" /> 35 <parameter name="@Createdate" layout="${longdate}" /> 36 <parameter name="@LogLevel" layout="${level}" /> 37 </target> 38 </targets> 39 40 <rules> 41 <!--根據日誌級別分別寫文件,也可以放一個文件中--> 42 <!--<logger name="DbLogger" levels="Debug,Info,Error" writeTo="MyFile" />--> 43 <logger name="MyLogger" level="Debug" writeTo="DebugFile" /> 44 <logger name="MyLogger" level="Info" writeTo="InfoFile" /> 45 <logger name="MyLogger" level="Error" writeTo="ErrorFile" /> 46 <!--寫資料庫--> 47 <logger name="MyLogger" levels="Trace,Debug,Info,Error" writeTo="NewDatabase"/> 48 </rules> 49 </nlog>NLog.config
- 如在根節點(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定義你所有需要的級別(多個用逗號分隔)。
- event-context代表自定義的參數。
路由規則(Rules)
<rules />區域定義了日誌的路由規則。每一個路由表項就是一個<logger />元素。<logger />有以下屬性:
- name - 日誌源/記錄者的名字 (允許使用通配符*)
- minlevel - 該規則所匹配日誌範圍的最低級別
- maxlevel - 該規則所匹配日誌範圍的最高級別
- level - 該規則所匹配的單一日誌級別
- levels - 該規則所匹配的一系列日誌級別,由逗號分隔。
- writeTo - 規則匹配時日誌應該被寫入的一系列目標,由逗號分隔。
- final - 標記當前規則為最後一個規則。其後的規則即時匹配也不會被運行
封裝
對NLog.config的Logger進行簡單封裝:
1 /// <summary> 2 /// 日誌類,只提供介面 3 /// 2018-11-6 15:32:01 4 /// </summary> 5 public class Logger 6 { 7 #region 初始化 8 //獲取指定的名稱為logger。 9 //private static NLog.Logger _dblogger = NLog.LogManager.GetLogger("MyLogger"); 10 /// <summary> 11 /// 日事件間類 12 /// </summary> 13 private LogEventInfo lei = new LogEventInfo(); 14 /// <summary> 15 /// 數據錯誤無法獲取用戶時使用 16 /// </summary> 17 public static string DefaultUser = "system"; 18 /// <summary> 19 /// 預設IP地址 20 /// </summary> 21 public static string DefaultIP = "127.0.0.1"; 22 /// <summary> 23 /// 提供日誌介面和實用程式功能 24 /// </summary> 25 private NLog.Logger _logger = null; 26 /// <summary> 27 /// 自定義日誌對象供外部使用 28 /// </summary> 29 public static Logger Default { get; private set; } 30 31 private Logger(NLog.Logger logger) 32 { 33 _logger = logger; 34 } 35 public Logger(string name) : this(LogManager.GetLogger(name)) 36 { } 37 38 static Logger() 39 { 40 //獲取具有當前類名稱的日誌程式。 41 Default = new Logger("MyLogger"); 42 } 43 #endregion 44 45 #region Debug 46 public void Debug(string msg, params object[] args) 47 { 48 _logger.Debug(msg, args); 49 } 50 51 public void Debug(string msg, Exception err) 52 { 53 _logger.Debug(err, msg); 54 } 55 #endregion 56 57 #region Info 58 public void Info(string msg, params object[] args) 59 { 60 _logger.Info(msg, args); 61 } 62 63 public void Info(string msg, Exception err) 64 { 65 _logger.Info(err, msg); 66 } 67 #endregion 68 69 #region Warn 70 /// <summary> 71 ///警告 72 /// </summary> 73 /// <param name="msg">警告信息</param> 74 /// <param name="args">動態參數</param> 75 public void Warn(string msg, params object[] args) 76 { 77 _logger.Warn(msg, args); 78 } 79 /// <summary> 80 ///警告 81 /// </summary> 82 /// <param name="msg">警告信息</param> 83 /// <param name="err">異常信息</param> 84 public void Warn(string msg, Exception err) 85 { 86 _logger.Warn(err, msg); 87 } 88 #endregion 89 90 #region Trace 91 /// <summary> 92 /// 使用指定的參數在跟蹤級別寫入診斷消息 93 /// </summary> 94 /// <param name="msg">跟蹤信息</param> 95 /// <param name="args">動態參數</param> 96 public void Trace(string msg, params object[] args) 97 { 98 _logger.Trace(msg, args); 99 } 100 /// <summary> 101 /// 使用指定的參數在跟蹤級別寫入診斷消息 102 /// </summary> 103 /// <param name="msg">跟蹤信息</param> 104 /// <param name="args">異常信息</param> 105 public void Trace(string msg, Exception err) 106 { 107 _logger.Trace(err, msg); 108 } 109 #endregion 110 111 #region Error 112 /// <summary> 113 /// 使用指定的參數在錯誤級別寫入診斷消息。 114 /// </summary> 115 /// <param name="msg">錯誤信息</param> 116 /// <param name="args">動態參數</param> 117 public void Error(string msg, params object[] args) 118 { 119 _logger.Error(msg, args); 120 } 121 /// <summary> 122 /// 使用指定的參數在錯誤級別寫入診斷消息。 123 /// </summary> 124 /// <param name="msg">錯誤信息</param> 125 /// <param name="args">異常信息</param> 126 public void Error(string msg, Exception err) 127 { 128 _logger.Error(err, msg); 129 } 130 #endregion 131 132 #region Fatal 133 /// <summary> 134 /// 使用指定的參數在致命級別寫入診斷消息。 135 /// </summary> 136 /// <param name="msg">致命錯誤</param> 137 /// <param name="args">動態參數</param> 138 public void Fatal(string msg, params object[] args) 139 { 140 _logger.Fatal(msg, args); 141 } 142 /// <summary> 143 /// 使用指定的參數在致命級別寫入診斷消息。 144 /// </summary> 145 /// <param name="msg">致命錯誤</param> 146 /// <param name="args">異常信息</param> 147 public void Fatal(string msg, Exception err) 148 { 149 _logger.Fatal(err, msg); 150 } 151 /// <summary> 152 /// 刷新所有掛起的日誌消息(在非同步目標的情況下)。 153 /// </summary> 154 /// <param name="timeoutMilliseconds">最大的時間允許沖洗。此後的任何消息都將被丟棄。</param> 155 public void Flush(int? timeoutMilliseconds = null) 156 { 157 if (timeoutMilliseconds != null) 158 NLog.LogManager.Flush(timeoutMilliseconds.Value); 159 160 NLog.LogManager.Flush(); 161 } 162 #endregion 163 164 165 #region Operator日誌寫入 166 /// <summary> 167 /// 寫入日誌信息 168 /// </summary> 169 /// <param name="operatorLogModel">操作信息</param> 170 public void InsOperatorLog(OperatorLogModel operatorLogModel) 171 { 172 var level = LogLevel.Info; 173 if (operatorLogModel.LogLevel == NLog.LogLevel.Trace) 174 level = LogLevel.Trace; 175 else if (operatorLogModel.LogLevel == NLog.LogLevel.Debug) 176 level = LogLevel.Debug; 177 else if (operatorLogModel.LogLevel == NLog.LogLevel.Info) 178 level = LogLevel.Info; 179 else if (operatorLogModel.LogLevel == NLog.LogLevel.Warn) 180 level = LogLevel.Warn; 181 else if (operatorLogModel.LogLevel == NLog.LogLevel.Error) 182 level = LogLevel.Error; 183 else if (operatorLogModel.LogLevel == NLog.LogLevel.Fatal) 184 level = LogLevel.Fatal; 185 186 if (operatorLogModel.LogMessage.Length > 3000) 187 { 188 operatorLogModel.LogMessage = operatorLogModel.LogMessage.Substring(0, 3000); 189 } 190 lei.Properties["Id"] = Guid.NewGuid().ToString("D"); 191 lei.Properties["AppName"] = operatorLogModel.AppName; 192 lei.Properties["ModuleName"] = operatorLogModel.ModuleName; 193 lei.Properties["ProcName"] = operatorLogModel.ProcName; 194 lei.Properties["OperationType"] = operatorLogModel.OperationType; 195 lei.Properties["Logger"] = operatorLogModel.Logger; 196 lei.Properties["LogMessage"] = operatorLogModel.LogMessage; 197 lei.Properties["IP"] = operatorLogModel.IP ?? DefaultIP; 198 lei.Properties["Longdate"] = operatorLogModel.Longdate; 199 lei.Properties["UserName"] = operatorLogModel.UserName ?? DefaultUser; 200 lei.Properties["Createdate"] = operatorLogModel.Createdate; 201 lei.Level = operatorLogModel.LogLevel; 202 _logger.Log(level, lei); 203 } 204 #endregion 205 }Logger
對操作類型進行簡單封裝,也可以自定義:
1 /// <summary> 2 /// 操作類型枚舉 3 /// </summary> 4 public enum OperationType 5 { 6 /// <summary> 7 /// 保存或添加 8 /// </summary> 9 [System.ComponentModel.Description("添加")] 10 ADD, 11 /// <summary> 12 /// 更新 13 /// </summary> 14 [System.ComponentModel.Description("更新")] 15 UPDATE, 16 /// <summary> 17 /// 核銷 18 /// </summary> 19 [System.ComponentModel.Description("核銷")] 20 AUDIT, 21 /// <summary> 22 /// 查看 23 /// </summary> 24 [System.ComponentModel.Description("指派")] 25 ASSIGN, 26 /// <summary> 27 /// 刪除 28 /// </summary> 29 [System.ComponentModel.Description("刪除")] 30 DELETE, 31 /// <summary> 32 /// 讀取/查詢 33 /// </summary> 34 [System.ComponentModel.Description("查詢")] 35 RETRIEVE, 36 /// <summary> 37 /// 登錄 38 /// </summary> 39 [System.ComponentModel.Description("登錄")] 40 LOGIN, 41 /// <summary> 42 /// 查看 43 /// </summary> 44 [System.ComponentModel.Description("查看")] 45 LOOK 46 }OperationType
自定義類,主要用於綁定數據:
1 /// <summary> 2 /// 操作日誌類 3 /// </summary> 4 public class OperatorLogModel 5 { 6 /// <summary> 7 /// 自增主鍵ID 8 /// </summary> 9 public string Id { get; set; } 10 /// <summary> 11 /// 一級菜單 12 /// </summary> 13 public string AppName { get; set; } 14 /// <summary> 15 /// 二級菜單 16 /// </summary> 17 public string ModuleName { get; set; } 18 /// <summary> 19 /// 本級菜單 20 /// </summary> 21 public string ProcName { get; set; } 22 /// <summary> 23 /// 操作類型 24 /// </summary> 25 public int OperationType { get; set; } 26 /// <summary> 27 /// 日誌文件 28 /// </summary> 29 public string Logger { get; set; } 30 /// <summary> 31 /// 日誌信息 32 /// </summary> 33 public string LogMessage { get; set; } 34 /// <summary> 35 /// IP地址 36 /// </summary> 37 public string IP { get; set; } 38 /// <summary> 39 /// 記錄時間 40 /// </summary> 41 public string Longdate { get; set; } 42 /// <summary> 43 /// 用戶名稱 44 /// </summary> 45 public string UserName { get; set; } 46 /// <summary> 47 /// 日誌級別 48 /// </summary> 49 public NLog.LogLevel LogLevel { get; set; } 50 /