1. 程式人生 > >C# 使用 log4net 日誌元件

C# 使用 log4net 日誌元件

一、 什麼是 log4net 

      Apache log4net 庫是幫助程式設計師將日誌語句輸出到各種輸出目標的工具,它是從Java中的Log4j遷移過來的一個.Net版的開源日誌框架。log4net 的一個顯著特徵是分層記錄器的概念,使用這些記錄器可以有選擇地控制任意粒度輸出日誌語句。主要特徵如下:

  • 支援多個框架
  • 輸出到多個日誌記錄目標
  • 分層日誌記錄體系結構
  • XML 配置
  • 動態配置
  • 日誌記錄上下文
  • 久經考驗的架構
  • 模組化和可擴充套件設計
  • 高效能和靈活性   

二、C# 使用 log4net

       新增Nuget 包,搜尋到“log4net”後 ,選擇安裝,具體如下圖所示:

三、新增 log4net 配置檔案

 使用 log4net需要我們配置log4net的配置檔案,目前,配置檔案是用 XML 編寫的。一般有兩種方式,一種是使用og4net自動生成的 “log4net.xml”進行配置,另一種是直接嵌入到執行程式的 app.config 檔案中。  

 具體內容如下:

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <configuration>
 3   <configSections>
 4     <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
 5   </configSections>
 6   <startup>
 7     <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
 8   </startup>
 9   <log4net>
10     <!-- OFF, FATAL, ERROR, WARN, INFO, DEBUG, ALL -->
11     <!-- Set root logger level to ERROR and its appenders -->
12     <root>
13       <level value="ALL" />
14       <appender-ref ref="SysAppender" />
15     </root>
16     <!-- Print only messages of level DEBUG or above in the packages -->
17     <logger name="WebLogger">
18       <level value="DEBUG" />
19     </logger>
20     <appender name="SysAppender" type="log4net.Appender.RollingFileAppender,log4net">
21       <param name="File" value="log/" />
22       <param name="AppendToFile" value="true" />
23       <param name="RollingStyle" value="Date" />
24       <param name="DatePattern" value="'demo_'yyyy_MM_dd-HH'.log'" />
25       <param name="StaticLogFileName" value="false" />
26       <param name="RollingStyle" value="Composite" />
27       <layout type="log4net.Layout.PatternLayout,log4net">
28         <param name="ConversionPattern" value="%date [th=%3thread] [line:%5L] [%-5level] %message%newline"/>
29       </layout>
30     </appender>
31     <appender name="consoleApp" type="log4net.Appender.ConsoleAppender,log4net">
32       <layout type="log4net.Layout.PatternLayout,log4net">
33         <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
34       </layout>
35     </appender>
36   </log4net>
37 </configuration>
View Code

        主要引數含義如下:

      

三、原始碼測試

       我們可以新增一個日誌類,專門用於輸出日誌列印,具體程式碼如下(注意:log4net目前暫時不支援通過配置檔案進行檔案刪除,可通過配置檔案設定檔案個數與大小進行覆蓋備份檔案。因此,自動刪除日誌需要程式碼實現):

  1  public static class LogUtil
  2     {
  3         private static log4net.ILog Log { get; } = log4net.LogManager.GetLogger("log");
  4 
  5         /// <summary>
  6         /// 日誌載入設定
  7         /// </summary>
  8         /// <param name="exeConfigFile">日誌配置檔名稱</param>
  9         /// <param name="day">保留天數,-1表示不刪除</param>
 10         public static void Configure(string exeConfigFile,int day=-1)
 11         {
 12             log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(exeConfigFile));
 13             if (day == -1) return;
 14             var files = new System.IO.DirectoryInfo("log").GetFiles();
 15             foreach (var file in files)
 16             {
 17                 // 定時刪除日誌檔案
 18                 if ((DateTime.Now - file.CreationTime).TotalDays > day)
 19                 {
 20                     file.Delete();
 21                 }
 22             }
 23         }
 24 
 25         private static string GetMethodName(int skipFrames = 2)
 26         {
 27             try
 28             {
 29                 // 這裡忽略skipFrames層堆疊,也就忽略了當前方法GetMethodName,以及呼叫此方法的方法,這樣拿到的就正好是外部呼叫列印日誌所在函式的方法資訊
 30                 var method = new StackFrame(skipFrames).GetMethod();
 31                 var properties =
 32                     method?.DeclaringType?.GetProperties(
 33                         BindingFlags.Instance |
 34                         BindingFlags.Static |
 35                         BindingFlags.Public |
 36                         BindingFlags.NonPublic);
 37                 var property = properties?.Where(p => p.GetGetMethod(true) == method || p.GetSetMethod(true) == method)
 38                     .FirstOrDefault();
 39 
 40                 var name = $"{method?.DeclaringType?.ToString().Split('.').Last()}.{method?.Name}";
 41                 return property == null
 42                     ? $"{name,-50}"
 43                     : $"{property.Name,-50}";
 44             }
 45             catch (Exception e)
 46             {
 47                 return "ERROR TO GET CALLING METHOD";
 48             }
 49         }
 50         private static string NoWarp(string msg)
 51         {
 52             return msg?.Replace("\r\n", " ").Replace("\n", " ");
 53         }
 54         private static string WrapException(string msg, Exception e)
 55         {
 56             var builder = new StringBuilder(msg);
 57             builder.Append("\t[").Append(e.Message).Append("]");
 58             if (e.InnerException != null)
 59             {
 60                 builder.Append(" --> [").Append(e.InnerException.Message).Append("]");
 61             }
 62 
 63             return builder.ToString();
 64         }
 65 
 66 
 67 
 68 
 69         public static void Debug(string msg)
 70         {
 71             Log.Debug(msg);
 72         }
 73         public static void Debug(string msg, Exception e)
 74         {
 75             Log.Debug(WrapException(msg, e), e);
 76         }
 77 
 78         public static void Info(string msg)
 79         {
 80             Log.Info(msg);
 81         }
 82         public static void Info(string msg, Exception e)
 83         {
 84             Log.Info(WrapException(msg, e), e);
 85         }
 86 
 87         public static void Warn(string msg)
 88         {
 89             Log.Warn(msg);
 90         }
 91         public static void Warn(string msg, Exception e)
 92         {
 93             Log.Warn(WrapException(msg, e), e);
 94         }
 95 
 96         public static void Error(string msg)
 97         {
 98             Log.Error(msg);
 99         }
100         public static void Error(string msg, Exception e)
101         {
102             Log.Error(WrapException(msg, e), e);
103         }
104 
105         public static void Fatal(string msg)
106         {
107             Log.Fatal(msg);
108         }
109         public static void Fatal(string msg, Exception e)
110         {
111             Log.Fatal(WrapException(msg, e), e);
112         }
113     }
View Code

       測試程式碼如下:

 1  static void Main(string[] args)
 2         {
 3             try
 4             {
 5                 string exeConfigFile = $"{AppDomain.CurrentDomain.BaseDirectory}//Log4netDemo.exe.config";
 6 
 7                 if (File.Exists(exeConfigFile) == false)
 8                 {
 9                     throw new Exception($"應用程式配置檔案 [{exeConfigFile}] 不存在,無法載入日誌 log4net 的配置");
10                 }
11 
12                 LogUtil.Configure(exeConfigFile,1);
13                 LogUtil.Info("====================================== Log4netDemo started, log4net setup...");
14                 LogUtil.Warn("程式啟動入參不合理");
15                 LogUtil.Error("程式啟動失敗");
16 
17                 Console.ReadKey();
18             }
19             catch (Exception ex)
20             {
21                 Console.WriteLine(ex);
22                 LogUtil.Error("程式載入失敗",ex);
23             }
24         }
View Code

 

       執行程式後,實際輸出效果如下:

        

 

 四、引用地址

  1.  http://logging.apache.org/log4net/release/manual/configuration.html
  2.  https://www.sohu.com/a/254335960_696685
  3.  https://blog.csdn.net/hr541659660/article/details/45575473