前言
在之前的.NET中,微軟還沒有提供過像樣的日志框架,目前能用的一些框架比如Log4Net、NLog、CommonLogging等,雖然多多少少使用起來有點費勁,但這里還是簡單分享一下Log4Net的初步使用方法。
在項目中的配置
第一步:首先在項目用引用Log4Net.dll.[管理NuGet程序包中直接搜索就可以啦]
第二步:Web.config文件中進行添加confIGsections的節點
<configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /> </configSections> </configuration>
第三步:在configSections下添加Log4Net配置節點[這里將日志分類了,以便於理解與查看對應的日志信息]

<log4net> <!--錯誤日志--> <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender"> <file value="log\\LogError\\" /> <appendToFile value="true" /> <rollingStyle value="Date" /> <datePattern value="yyyy\\yyyyMM\\yyyyMMdd'.txt'" /> <staticLogFileName value="false" /> <param name="MaxSizeRollBackups" value="100" /> <layout type="log4net.Layout.PatternLayout"> <!--每條日志末尾的文字說明--> <!--輸出格式--> <!--樣例:2008-03-26 13:42:32,111 [10] INFO Log4NetDemo.MainClass [(null)] - info--> <conversionPattern value="%newline %n記錄時間:%date %n線程ID:[%thread] %n日志級別: %-5level %n錯誤描述:%message%newline %n" /> </layout> </appender> <!--Info日志--> <appender name="InfoAppender" type="log4net.Appender.RollingFileAppender"> <param name="File" value="Log\\LogInfo\\" /> <param name="AppendToFile" value="true" /> <param name="MaxFileSize" value="10240" /> <param name="MaxSizeRollBackups" value="100" /> <param name="StaticLogFileName" value="false" /> <param name="DatePattern" value="yyyy\\yyyyMM\\yyyyMMdd'.txt'" /> <param name="RollingStyle" value="Date" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%newline %n記錄時間:%date %n線程ID:[%thread] %n日志級別: %-5level %n日志描述:%message%newline %n" /> </layout> </appender> <!--監控日志--> <appender name="MonitorAppender" type="log4net.Appender.RollingFileAppender"> <param name="File" value="Log\\LogMonitor\\" /> <param name="AppendToFile" value="true" /> <param name="MaxFileSize" value="10240" /> <param name="MaxSizeRollBackups" value="100" /> <param name="StaticLogFileName" value="false" /> <param name="DatePattern" value="yyyy\\yyyyMM\\yyyyMMdd'.txt'" /> <param name="RollingStyle" value="Date" /> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%newline %n記錄時間:%date %n線程ID:[%thread] %n日志級別: %-5level %n跟蹤描述:%message%newline %n" /> </layout> </appender> <!--Error日志--> <logger name="LogError"> <level value="ERROR" /> <appender-ref ref="RollingLogFileAppender" /> </logger> <!--Info日志--> <logger name="LogInfo"> <level value="INFO" /> <appender-ref ref="InfoAppender" /> </logger> <!--監控日志--> <logger name="LogMonitor"> <level value="Monitor" /> <appender-ref ref="MonitorAppender" /> </logger> </log4net>
在框架的體系里,所有的日志對象都是根日志(root logger)的后代。 因此如果一個日志對象沒有在配置文件里顯式定義,則框架使用根日志中定義的屬性。在<root>標簽里,可以定義level級別值和Appender的列表。如果沒有定義LEVEL的值,則缺省為DEBUG。可以通過<appender-ref>標簽定義日志對象使用的Appender對象。<appender-ref>聲明了在其他地方定義的Appender對象的一個引用。在一個logger對象中的設置會覆蓋根日志的設置。而對Appender屬性來說,子日志對象則會繼承父日志對象的Appender列表。這種缺省的行為方式也可以通過顯式地設定<logger>標簽的additivity屬性為false而改變。
在項目中建立自定義Log日志
第四步:在文件里配置以下類:ApiTrackerFilter.cs[Api接口日志],TrackerFilter.cs[基本日志類],LoggerHelper.cs[日志信息處理類],MonitorLog.cs[監控日志類](對於監控日志,則根據個人需求是否建立),其中的BookException是自定義的錯誤,可以省略。

public class LoggerHelper { private static readonly log4net.ILog LogInfo = log4net.LogManager.GetLogger("LogInfo"); private static readonly log4net.ILog LogError = log4net.LogManager.GetLogger("LogError"); private static readonly log4net.ILog LogMonitor = log4net.LogManager.GetLogger("LogMonitor"); /// <summary> /// 記錄Error日志 /// </summary> /// <param name="errorMsg"></param> /// <param name="ex"></param> public static void Error(string errorMsg, Exception ex = null) { if (ex != null) { LogError.Error(errorMsg, ex); } else { LogError.Error(errorMsg); } } /// <summary> /// 記錄Info日志 /// </summary> /// <param name="msg"></param> /// <param name="ex"></param> public static void Info(string msg, Exception ex = null) { if (ex != null) { LogInfo.Info(msg, ex); } else { LogInfo.Info(msg); } } /// <summary> /// 記錄Monitor日志 /// </summary> /// <param name="msg"></param> public static void Monitor(string msg) { LogMonitor.Info(msg); } }

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public class TrackerFilter : ActionFilterAttribute, IExceptionFilter { private readonly string key = "_thisOnActionMonitorLog_"; #region Action時間監控 public override void OnActionExecuting(ActionExecutingContext filterContext) { MonitorLog monLog = new MonitorLog(); monLog.ExecuteStartTime = Convert.ToDateTime(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.ffff", DateTimeFormatInfo.InvariantInfo)); monLog.ControllerName = filterContext.RouteData.Values["controller"] as string; monLog.ActionName = filterContext.RouteData.Values["action"] as string; filterContext.Controller.ViewData[this.key] = monLog; } public override void OnActionExecuted(ActionExecutedContext filterContext) { MonitorLog monLog = filterContext.Controller.ViewData[this.key] as MonitorLog; monLog.ExecuteEndTime = DateTime.Now; monLog.FormCollections = filterContext.HttpContext.Request.Form;//form表單提交的數據 monLog.QueryCollections = filterContext.HttpContext.Request.QueryString;//Url 參數 LoggerHelper.Monitor(monLog.GetLogInfo()); } #endregion #region View 視圖生成時間監控 public override void OnResultExecuting(ResultExecutingContext filterContext) { MonitorLog monLog = filterContext.Controller.ViewData[this.key] as MonitorLog; monLog.ExecuteStartTime = DateTime.Now; } public override void OnResultExecuted(ResultExecutedContext filterContext) { MonitorLog monLog = filterContext.Controller.ViewData[this.key] as MonitorLog; monLog.ExecuteEndTime = DateTime.Now; LoggerHelper.Monitor(monLog.GetLogInfo(MonitorLog.MonitorType.View)); filterContext.Controller.ViewData.Remove(this.key); } #endregion #region 錯誤日志 public void OnException(ExceptionContext filterContext) { if (!filterContext.ExceptionHandled) { string controllerName = string.Format("{0}Controller", filterContext.RouteData.Values["controller"] as string); string actionName = filterContext.RouteData.Values["action"] as string; string errorMsg = string.Format("在執行 controller[{0}] 的 action[{1}] 時產生異常", controllerName, actionName); LoggerHelper.Error(errorMsg, filterContext.Exception); } } #endregion }

/// <summary> /// 監控日志對象 /// </summary> public class MonitorLog { public MonitorLog() { this.Watch = new Stopwatch(); this.Watch.Start(); } /// <summary> /// 監控類型 /// </summary> public enum MonitorType { /// <summary> /// Action /// </summary> Action = 1, /// <summary> /// 視圖 /// </summary> View = 2 } public string ControllerName { get; set; } public string ActionName { get; set; } public Stopwatch Watch { get; set; } public DateTime ExecuteStartTime { get; set; } public DateTime ExecuteEndTime { get; set; } /// <summary> /// Form 表單數據 /// </summary> public NameValueCollection FormCollections { get; set; } /// <summary> /// URL 參數 /// </summary> public NameValueCollection QueryCollections { get; set; } /// <summary> /// 文本流 /// </summary> public string Raw { get; set; } /// <summary> /// 獲取監控指標日志 /// </summary> /// <param name="mtype"></param> /// <returns></returns> public string GetLogInfo(MonitorType mtype = MonitorType.Action) { this.Watch.Stop(); string actionView = "Action執行時間監控:"; string action = "Action"; if (mtype == MonitorType.View) { actionView = "View視圖生成時間監控:"; action = "View"; } string msgContent = string.Format( @" {0} ControllerName:{1}Controller {2}Name:{3} 開始時間:{4} 結束時間:{5} 總 時 間:{6}秒", actionView, this.ControllerName, action, this.ActionName, this.ExecuteStartTime, this.ExecuteEndTime, this.Watch.ElapsedMilliseconds); if (!string.IsNullOrEmpty(this.Raw)) { msgContent += @" Raw:" + this.Raw; } else if (this.FormCollections != null) { msgContent += @" Form:" + this.GetCollections(this.FormCollections); } else if (this.QueryCollections != null) { msgContent += @" Query:" + this.GetCollections(this.QueryCollections); } return msgContent; } /// <summary> /// 獲取Post 或Get 參數 /// </summary> /// <param name="collections"></param> /// <returns></returns> public string GetCollections(NameValueCollection collections) { string parameters = string.Empty; if (collections == null || collections.Count == 0) { return parameters; } parameters = collections.Keys.Cast<string>() .Aggregate(parameters, (current, key) => current + string.Format("{0}={1}&", key, collections[key])); if (!string.IsNullOrWhiteSpace(parameters) && parameters.EndsWith("&")) { parameters = parameters.Substring(0, parameters.Length - 1); } return parameters; }

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public class ApiTrackerFilter : ActionFilterAttribute { private readonly string key = "_thisOnApiActionMonitorLog_"; public override void OnActionExecuting(HttpActionContext actionContext) { var monLog = new MonitorLog(); monLog.ExecuteStartTime = Convert.ToDateTime(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.ffff", DateTimeFormatInfo.InvariantInfo)); monLog.ControllerName = actionContext.ActionDescriptor.ControllerDescriptor.ControllerName; monLog.ActionName = actionContext.ActionDescriptor.ActionName; actionContext.Request.Properties[this.key] = monLog; } public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) { if (actionExecutedContext.Exception != null) { string controllerName = string.Format( "{0}Controller", actionExecutedContext.ActionContext.ActionDescriptor.ControllerDescriptor.ControllerName); string actionName = actionExecutedContext.ActionContext.ActionDescriptor.ActionName; string errorMsg = string.Format("在執行 controller[{0}] 的 action[{1}] 時產生異常", controllerName, actionName); if (actionExecutedContext.Exception is BookException) { LoggerHelper.Info(errorMsg, actionExecutedContext.Exception); } else { LoggerHelper.Error(errorMsg, actionExecutedContext.Exception); } } if (!actionExecutedContext.Request.Properties.ContainsKey(this.key)) { return; } var monLog = actionExecutedContext.Request.Properties[this.key] as MonitorLog; if (monLog != null) { monLog.ExecuteEndTime = DateTime.Now; monLog.Raw = actionExecutedContext.Request.Content.ReadAsStringAsync().Result; LoggerHelper.Monitor(monLog.GetLogInfo()); } } }
在Global.asax文件中配置以及在MVC的FilterConfig過濾器中配置信息
經過這么多的准備工作,終於最后一步:
1.Global.axax中配置
protected void Application_Start(object sender, EventArgs e) { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); log4net.Config.XmlConfigurator.Configure(); GlobalConfiguration.Configuration.Filters.Add(new Log.ApiTrackerFilter()); BundleConfig.RegisterBundles(BundleTable.Bundles); }
2.在FilterConfig過濾器中配置信息
public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //監控日志 filters.Add(new Log.TrackerFilter()); filters.Add(new HandleErrorAttribute()); }
至此,所有都成功了,最后運行的結果可以在項目根目錄下查看相應日期的Log日志信息。