在Web应用运行过程中,我们难免会遇到程序运行异常,这个时候我们就应该将异常信息记录下来,以便开发人员和维护人员对异常原因进行还原,对异常原因进行修复。在ASP.NET平台中进行日志记录的组件也有很多,如Log4Net、CommonLogging等,我们这里选用Log4Net进行异常日志的记录。
捕获异常 在ASP.NET MVC中提供了一个全局的异常处理过滤器:HandleErrorAttribute,可以通过该过滤器捕获异常信息。
我们在Models文件夹下新建类型Log4ExceptionAttribute,继承HandleErrorAttribute类,同时重写OnException方法来捕获异常数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 using System.Web.Mvc;namespace PMS.WebApp.Models { public class Log4ExceptionAttribute :HandleErrorAttribute { public override void OnException (ExceptionContext filterContext ) { base .OnException(filterContext); var ex = filterContext.Exception; } } }
新建过滤器后我们还需要在Global文件中调用的RegisterGlobalFilters方法中完成自己定义异常处理过滤的注册。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 using System.Web.Mvc;using PMS.WebApp.Models;namespace PMS.WebApp { public class FilterConfig { public static void RegisterGlobalFilters (GlobalFilterCollection filters ) { filters.Add(new Log4ExceptionAttribute()); } } }
队列处理 考虑到多用户并发操作时可能产生的问题,我们需要新建一个队列来进行异常信息的暂存,同时开辟一个线程专门对队列中的异常信息进行处理。
在Log4ExceptionAttribute类中新建一个静态的异常类型的队列,在发生异常后,程序自动触发OnException方法,方法中将当前的异常信息入队后,跳转到错误页面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 using System;using System.Collections.Generic;using System.Web.Mvc;namespace PMS.WebApp.Models { public class Log4ExceptionAttribute :HandleErrorAttribute { public static Queue<Exception> Exceptions=new Queue<Exception>(); public override void OnException (ExceptionContext filterContext ) { base .OnException(filterContext); var ex = filterContext.Exception; Exceptions.Enqueue(ex); filterContext.HttpContext.Response.Redirect("/Error.html" ); } } }
Log4Net的配置是在应用程序配置文件中进行的,我们先在配置文件中进行Log4Net的配置。Log4Net需要配置的节点位置和SpringNet完全相同,首先需要在configSessions中新增子节点,然后在configuration节点中增加log4net节点完成具体配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 <configuration > <configSections > <section name ="entityFramework" type ="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission ="false" /> <section name ="log4net" type ="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /> <sectionGroup name ="spring" > <section name ="context" type ="Spring.Context.Support.MvcContextHandler, Spring.Web.Mvc4" /> </sectionGroup > </configSections > <spring > <context > <resource uri ="file://~/Config/controllers.xml" /> <resource uri ="file://~/Config/services.xml" /> </context > </spring > <log4net > <root > <level value ="ALL" /> <appender-ref ref ="SysAppender" /> </root > <logger name ="WebLogger" > <level value ="DEBUG" /> </logger > <appender name ="SysAppender" type ="log4net.Appender.RollingFileAppender,log4net" > <param name ="File" value ="App_Data/" /> <param name ="AppendToFile" value ="true" /> <param name ="RollingStyle" value ="Date" /> <param name ="DatePattern" value ="" Logs_" yyyyMMdd" .txt" " /> <param name ="StaticLogFileName" value ="false" /> <layout type ="log4net.Layout.PatternLayout,log4net" > <param name ="ConversionPattern" value ="%d [%t] %-5p %c - %m%n" /> <param name ="Header" value =" ----------------------header-------------------------- " /> <param name ="Footer" value =" ----------------------footer-------------------------- " /> </layout > </appender > <appender name ="consoleApp" type ="log4net.Appender.ConsoleAppender,log4net" > <layout type ="log4net.Layout.PatternLayout,log4net" > <param name ="ConversionPattern" value ="%d [%t] %-5p %c - %m%n" /> </layout > </appender > </log4net > ... </configuration >
进阶配置 在配置文件中可以对日志记录的信息、格式、文件名等作出具体的配置,下面是配置信息的详解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 <?xml version="1.0" ?> <configuration > <configSections > <section name ="log4net" type ="log4net.Config.Log4NetConfigurationSectionHandler,log4net" /> </configSections > <log4net > <root > <level value ="ERROR" /> <appender-ref ref ="RollingFileAppender" /> </root > <appender name ="RollingFileAppender" type ="log4net.Appender.RollingFileAppender" > <file value ="c:\Log\TestLog4net.TXT" /> <lockingModel type ="log4net.Appender.FileAppender+MinimalLock" /> <datePattern value ="(yyyyMMdd)" /> <appendToFile value ="true" /> <RollingStyle value ="Size" /> <MaxSizeRollBackups value ="10" /> <maximumFileSize value ="2MB" /> <layout type ="log4net.Layout.PatternLayout" > <conversionPattern value ="%date [%t]%-5p %c - %m%n" /> </layout > </appender > </log4net > </configuration >
在Global文件中的Application_Start方法中开启一个线程,用于将队列中的错误信息写入日志文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 using System.Linq;using System.Threading;using System.Web.Http;using System.Web.Mvc;using System.Web.Optimization;using System.Web.Routing;using log4net;using PMS.WebApp.Models;using Spring.Web.Mvc;namespace PMS.WebApp { public class MvcApplication : SpringMvcApplication { protected void Application_Start () { log4net.Config.XmlConfigurator.Configure(); AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); var filePath = Server.MapPath("/Log/" ); ThreadPool.QueueUserWorkItem((a) => { while (true ) { if (Log4ExceptionAttribute.Exceptions.Any()) { var ex = Log4ExceptionAttribute.Exceptions.Dequeue(); if (ex == null ) continue ; var logger = LogManager.GetLogger("errorMsg" ); logger.Error(ex.ToString()); } else { Thread.Sleep(3000 ); } } }, filePath); } } }
成功完成错误日志的配置。