簡單介紹一下log4net的主要組成,詳細說明可以參考https://blog.csdn.net/binnygoal/article/details/79557746
1.Logger
Logger是直接和應用程序交互的組件,是負責日志的記錄者,可以同時存在多個Logger,然后由它引用的Appender記錄到指定的媒介,並由Layout控制輸出格式。
2.Appender
Appender用來定義日志的輸出方式,即提供記錄介質,如記錄到數據庫,記錄到本地文件,輸出到控制台等等。
3.Layout
Layout用於控制Appender的輸出格式(格式化記錄數據),可以是線性的也可以是XML。
4.Filter
Filter負責記錄篩選,可以過濾掉Appender輸出的內容。
總體流程:Logger發出記錄信息,Appender接到信息,根據內部的Layout配置對記錄信息格式化,然后根據Filter對記錄信息進行篩選,最后將其記錄到指定介質中。
簡單配置log4net
第一步:在項目中添加log4net.dll的引用;
第二步:配置log4net.config文件;
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /> </configSections> <log4net> <logger name="ErrorLogger"> <level value="WARN" /> <appender-ref ref="ErrorAppender" /> </logger> <logger name="DebugLogger"> <level value="DEBUG" /> <appender-ref ref="DebugAppender" /> </logger> <logger name="InfoLogger"> <level value="INFO" /> <appender-ref ref="InfoAppender" /> </logger> <appender name="InfoAppender" type="log4net.Appender.RollingFileAppender"> <!--日志文件路徑,文件夾不存在則新建 --> <file value="D://THS//logs//" /> <!--是否追加到文件--> <appendToFile value="true" /> <!--記錄日志寫入文件時,不鎖定文本文件,防止多線程時不能寫Log,官方說線程非安全--> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <!--最多產生的日志文件數,超過則只保留最新的n+1個--> <maxSizeRollBackups value="1" /> <!--每個文件的大小,只在混合方式與文件大小方式下使用,超出大小后在所有文件名后自動增加正整數重新命名,數字最大的最早寫入,沒帶數字最晚寫入--> <maximumFileSize value="256MB" /> <!--是否只寫到一個文件中--> <staticLogFileName value="false"/> <!--按照何種方式產生多個日志文件(日期[Date],文件大小[Size],混合[Composite])--> <rollingStyle value="Composite" /> <!--是否保存日志文件的擴展名--> <preserveLogFileNameExtension value="true" /> <!--按日期產生文件夾,文件名固定。注意" 的位置--> <datePattern value="yyyy-MM-dd/"SysInfo.log"" /> <!--記錄的格式。一般用log4net.Layout.PatternLayout布局--> <!--此處用繼承了log4net.Layout.PatternLayout的自定義布局,LogTest.Log為命名空間。%Property{LineLocation}、%Property{Method}等是自定義的輸出--> <layout type="LogTest.Log.Z_PatternLayout"> <conversionPattern value="日志時間:%Property{Time} %n記錄方法:[%thread]%Property{Method} Line:%Property{LineLocation} %n日志信息:%Property{Message} %n%n" /> </layout> <!--過濾設置,LevelRangeFilter為使用的過濾器。--> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="INFO" /> <param name="LevelMax" value="INFO" /> </filter> </appender> <appender name="DebugAppender" type="log4net.Appender.RollingFileAppender"> <file value="D://THS//logs//" /> <appendToFile value="true" /> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <maxSizeRollBackups value="30" /> <staticLogFileName value="false"/> <rollingStyle value="Date" /> <preserveLogFileNameExtension value="true" /> <datePattern value="yyyy-MM-dd/"SysDebug.log"" /> <layout type="LogTest.Log.Z_PatternLayout"> <conversionPattern value="日志時間:%Property{Time} %n記錄方法:[%thread]%Property{Method} Line:%Property{LineLocation} %n日志信息:%Property{Message} %n%n" /> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="DEBUG" /> <param name="LevelMax" value="DEBUG" /> </filter> </appender> <appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender"> <file value="D:/THS/logs/" /> <appendToFile value="true" /> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <maxSizeRollBackups value="30" /> <staticLogFileName value="false"/> <rollingStyle value="Date" /> <preserveLogFileNameExtension value="true" /> <datePattern value="yyyy-MM-dd/"SysError.log"" /> <layout type="LogTest.Log.Z_PatternLayout"> <conversionPattern value="日志時間:%Property{Time} %n日志級別:%-5level %n記錄方法:[%thread]%Property{Method} Line:%Property{LineLocation} %n日志信息:%Property{Message} %n異常信息:%exception %n%n" /> </layout> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="WARN" /> <param name="LevelMax" value="FATAL" /> </filter> </appender> </log4net> </configuration>
注意,注意,注意:修改log4net.config文件屬性“復制到輸出目錄”為“始終復制”,否則不會生成日志文件夾;
第三步:如果是使用自動以配置文件,則在AssemblyInfo.cs中添加關聯配置文件代碼
// 使用配置文件log4net.config,監視改變 [assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
如果是在默認App.config文件中配置log4net,則可以直接在Program.cs中的Main方法中添加:
log4net.Config.XmlConfigurator.Configure();
第四步:自定義擴展輸出,通過繼承log4net.Layout.PatternLayout類,使用log4net.Core.LoggingEvent類的方法得到了要輸出的LogEntity類的名稱,然后通過反射得到各個屬性的值,使用PatternLayout類AddConverter方法傳入得到的值。注意Appender中的Layout type要引用用到的類的命名空間以及類名。
1.創建LogEntity實體類(自定義輸出屬性)
namespace LogTest.Log { public class Z_LogEntity { /// <summary> /// 引發日志事件的行號 /// </summary> public string LineLocation { get; set; } /// <summary> /// 應用程序提供給日志事件的消息 /// </summary> public string Message { get; set; } /// <summary> /// 引發日志事件的方法(包括類名和方法名) /// </summary> public string Method { get; set; } /// <summary> /// 引發日志事件的時間(格式化) /// </summary> public string Time { get; set; } } }
2.繼承PatternLayoutConvert重寫轉換器
using log4net.Core; using log4net.Layout.Pattern; using System.IO; using System.Reflection; namespace LogTest.Log { public class Z_PatternConvert : PatternLayoutConverter { protected override void Convert(TextWriter writer, LoggingEvent loggingEvent) { if (Option != null) // 寫入指定鍵的值 WriteObject(writer, loggingEvent.Repository, LookupProperty(Option, loggingEvent)); else // 寫入所有關鍵值對 WriteDictionary(writer, loggingEvent.Repository, loggingEvent.GetProperties()); } /// <summary> /// 通過反射獲取傳入的日志對象的某個屬性 /// </summary> private object LookupProperty(string property, LoggingEvent loggingEvent) { object propertyValue = string.Empty; PropertyInfo propertyInfo = loggingEvent.MessageObject.GetType().GetProperty(property); if (propertyInfo != null) propertyValue = propertyInfo.GetValue(loggingEvent.MessageObject, null); return propertyValue; } } }
3.繼承PatternLayout,添加轉換器到實例中
using log4net.Layout; namespace LogTest.Log { public class Z_PatternLayout : PatternLayout { public Z_PatternLayout() { this.AddConverter("Property", typeof(Z_PatternConvert)); } } }
第五步:編寫LogHelper類
using System; using System.Diagnostics; using System.Runtime.CompilerServices; namespace LogTest.Log { public class LogHelper { /// <summary> /// 靜態只讀實例化對象DebugLogger /// </summary> public static readonly log4net.ILog DebugLog = log4net.LogManager.GetLogger("DebugLogger"); /// <summary> /// 靜態只讀實例化對象ErrorLogger /// </summary> public static readonly log4net.ILog ErrorLog = log4net.LogManager.GetLogger("ErrorLogger"); /// <summary> /// 靜態只讀實例化對象InfoLogger /// </summary> public static readonly log4net.ILog InfoLog = log4net.LogManager.GetLogger("InfoLogger"); private static Z_LogEntity logEntity = new Z_LogEntity(); public static Z_LogEntity BuildLogEntity(string message, [CallerLineNumber] int lineNum = 0, [CallerMemberName] string method = "") { logEntity.Time = DateTime.Now.ToString("HH:mm:ss:fff"); logEntity.Message = message; logEntity.LineLocation = lineNum.ToString(); logEntity.Method = (new StackTrace()).GetFrame(1).GetMethod().ReflectedType.Name + "." + method; return logEntity; } public static void WriteInfo(Z_LogEntity logEntity) { try { if (InfoLog.IsInfoEnabled) { InfoLog.Info(logEntity); } } catch { } } public static void WriteDebug(Z_LogEntity logEntity) { try { if (DebugLog.IsDebugEnabled) { DebugLog.Debug(logEntity); } } catch { } } public static void WriteWarn(Z_LogEntity logEntity) { try { if (ErrorLog.IsWarnEnabled) { ErrorLog.Warn(logEntity); } } catch { } } public static void WriteWarn(Z_LogEntity logEntity, Exception ex) { try { if (ErrorLog.IsWarnEnabled) { ErrorLog.Warn(logEntity, ex); } } catch { } } public static void WriteError(Z_LogEntity logEntity) { try { if (ErrorLog.IsErrorEnabled) { ErrorLog.Error(logEntity); } } catch { } } public static void WriteError(Z_LogEntity logEntity, Exception ex) { try { if (ErrorLog.IsErrorEnabled) { ErrorLog.Error(logEntity, ex); } } catch { } } public static void WriteFatal(Z_LogEntity logEntity) { try { if (ErrorLog.IsFatalEnabled) { ErrorLog.Fatal(logEntity); } } catch { } } public static void WriteFatal(Z_LogEntity logEntity, Exception ex) { try { if (ErrorLog.IsFatalEnabled) { ErrorLog.Fatal(logEntity, ex); } } catch { } } } }
第六步:程序中使用
// 記錄Info級別數據 LogHelper.WriteInfo(LogHelper.BuildLogEntity("程序運行記錄寫入!")); // 記錄Debug級別數據 LogHelper.WriteDebug(LogHelper.BuildLogEntity("調試信息數據寫入!")); // 記錄Warn級別數據 LogHelper.WriteWarn(LogHelper.BuildLogEntity("警告數據寫入!"),new Exception("對應的錯誤信息!")); // 記錄Error級別數據 LogHelper.WriteError(LogHelper.BuildLogEntity("一般錯誤數據寫入!"), new Exception("對應的錯誤信息!")); // 記錄Fatal級別數據 LogHelper.WriteFatal(LogHelper.BuildLogEntity("致命錯誤數據寫入!"), new Exception("對應的錯誤信息!"));