zoukankan      html  css  js  c++  java
  • 在ASP.NET MVC 3中使用日志记录组件Elmah和NLog

        Elmah:主要针对Web应用程序,全局性地捕获应用程序中未处理的异常。

        NLog:通用的日志记录组件,与Log4Net属于同类组件。相对于Elmah更通用,不局限于Web应用程序,还可以区分日志级别(详见“使用NLog”一节),但是在错误日志记录方面,需要花费比较多的工夫才能实现Elmah提供的功能。

        在ASP.NET MVC应用程序中可以考虑使用这Elmah+NLog进行互补,也可以使用NLog+HandleErrorAttribute实现所有日志的记录。下面就说明一下如何使用Elmah和NLog。

    使用Elmah

    一、安装与基本配置

    1、使用Nuget安装Elmah组件

    ElMAH和ELMAH Core Library是必需的组件,如果没有安装ELMAH on MS SQL Sever组件,错误日志将被记录在内存里,一旦应用程序重启,日志就会丢失。这些组件安装之后,会在Web.Config文件中添加一些默认的配置。

    2、修改ELMAH的配置。

        1)修改ELMAH的数据库连接。

    1 <connectionStrings>    
    2   <add name="elmah-sqlserver" connectionString="server=(local);Initial Catalog=PE.LayerArtitecture;Integrated Security=True;" providerName="System.Data.SqlClient" /> 
    3 </connectionStrings> 

        2)启用自定义错误页。

        在<system.web>节点下添加:

    <system.web> 
        <httpModules> 
          <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" /> 
          <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" /> 
          <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" /> 
        </httpModules> 
        <customErrors mode="On" defaultRedirect="GenericErrorPage.html" /> 
    </system.web>
     说明: GenericErrorPage.html需要自己创建。

         3)创建数据表

    CREATE TABLE [dbo].[ELMAH_Error]( 
        [ErrorId] [uniqueidentifier] NOT NULL CONSTRAINT [DF_ELMAH_Error_ErrorId]  DEFAULT (newid()), 
        [Application] [nvarchar](60) NOT NULL, 
        [Host] [nvarchar](50) NOT NULL, 
        [Type] [nvarchar](100) NOT NULL, 
        [Source] [nvarchar](60) NOT NULL, 
        [Message] [nvarchar](500) NOT NULL, 
        [User] [nvarchar](50) NOT NULL, 
        [StatusCode] [int] NOT NULL, 
        [TimeUtc] [datetime] NOT NULL, 
        [Sequence] [int] IDENTITY(1,1) NOT NULL, 
        [AllXml] [ntext] NOT NULL, 
     CONSTRAINT [PK_ELMAH_Error] PRIMARY KEY NONCLUSTERED 
    ( 
        [ErrorId] ASC 
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY] 
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 
    至此,即完成了ELMAH的基本配置。

    二、查看错误日志

    1、在视图上添加一个不存在的Action链接。

    <table> 
        <thead> 
            <td>分类名称</td> 
            <td>描述</td> 
        </thead> 
        @Html.ActionLink("Error Handle Sample", "Index1"); 
    </table> 

    2、点击链接“Error Handle Sample”,正常情况下,会出现异常黄屏页面,因为Index1这个Action并不存在。但是因为使用了Elmah进行全局异常控制,所以会跳转到错误页面,并将异常信息记录到错误日志中(需要一定的配置,后面会介绍)。


    3、查看错误日志

     

        1)点击Details,可以看到报错黄屏信息:


        2)还可以查看报错时,服务器以及客户端的信息:

    三、禁止非授权用户查看日志

    在Web.Config中,去掉授权配置的注释:

    配置完之后,非“admin”角色的用户就会被重定向到登录页。

    四、替换掉ASP.NET自带的HandleErrorAttribute过滤器

    在Controller的某个Action中使用"Throw new Exception("出错了!")"显示地抛出一个异常,你会发现Elmah并不会记录这个异常,这是因为ASP.NET MVC默认在Global.asax中全局注册了HandleErrorAttribute过滤器,所以程序中出现的异常都会被其捕获;但是,HandleErrorAttribute没有日志记录,所以使用Elmah替换HandleErrorAttribute也是一种常用的做法。实现步骤如下:

    1、安装Nuget组件Elmah.MVC

    2、确保FilterConfig.cs或者Global.asax中没有注册HandleErrorAttribute(实际上Elmah.MVC组件已经注册了,但是可以通过配置文件控制是否启用该过滤器),也就是说,没有下面这句代码:

    filters.Add(new HandleErrorAttribute()); 

    3、按以下参数值配置Web.Config文件

    <appSettings> 
      <add key="webpages:Version" value="2.0.0.0" /> 
      <add key="webpages:Enabled" value="false" /> 
      <add key="PreserveLoginUrl" value="true" /> 
      <add key="ClientValidationEnabled" value="true" /> 
      <add key="UnobtrusiveJavaScriptEnabled" value="true" /> 
      <add key="elmah.mvc.disableHandler" value="false" /> 
      <add key="elmah.mvc.disableHandleErrorFilter" value="true" /> 
      <add key="elmah.mvc.requiresAuthentication" value="false" /> 
      <add key="elmah.mvc.allowedRoles" value="*" /> 
      <add key="elmah.mvc.route" value="elmah" /> 
    </appSettings> 

        elmah.mvc.disableHandleErrorFilter:是否“禁止使用HandleErrorAttribute”,这里应设置为true;

    使用NLog

    一、安装NLog组件

    通过NGet安装以下三个包:

    Nlog包含了日志记录的主要功能,Nlog Configuration为你创建一个Nlog需要使用的空NLog.config文件,NLog Schema for intellisense(TM)在编辑NLog.config时提供智能提示。

    二、日志组件API

    在日志组件中用得最多的两个类分别是NLog命名空间下的Logger和LoggerManager。Logger代表已经命名的日志来源,并且提供了发出日志信息的方法,而LoggerManager则提供了创建和管理Logger的实例。

        需要理解的一点是,Logger只代表日志源信息,而不关心日志的输出位置。日志的输出位置是通过配置文件或者配置API来设置的。

    三、创建Logger实例

    // 方法1: 
    using NLog; 
    Logger logger = LogManager.GetLogger("MyClassName"); 
                                             
    // 方法2: 
    namespace MyNamespace 
    { 
      public class MyClass 
      { 
        private static Logger logger = LogManager.GetCurrentClassLogger(); 
      } 
    } 

    四、日志级别

    每条日志消息都有与之关联的日志级别,用来表示该日志有多重要/详细。NLog能够基于Logger的名称和级别来路由(也就是说,确定哪些的日志需要记录到哪些位置)日志消息。

    NLog支持以下的日志级别:

    • Trace - 很细节的信息。一般在开发环境中使用。

    • Debug -  调试信息, 用得比Trace少, 一般不会再产品环境中使用。

    • Info - 信息消息,一般在产品环境中启用。 information messages, which are normally enabled in production environment

    • Warn - 警告消息, 一般用于非关键性的问题,可以恢复或者是临时性的失败。

    • Error - 错误消息

    • Fatal - 非常严重的错误

    五、发出错误消息

    using NLog; 
                                      
    public class MyClass 
    { 
      private static Logger logger = LogManager.GetCurrentClassLogger(); 
                                      
      public void MyMethod1() 
      { 
        logger.Trace("Sample trace message"); 
        logger.Debug("Sample debug message"); 
        logger.Info("Sample informational message"); 
        logger.Warn("Sample warning message"); 
        logger.Error("Sample error message"); 
        logger.Fatal("Sample fatal error message"); 
                                      
        // alternatively you can call the Log() method 
        // and pass log level as the parameter. 
        logger.Log(LogLevel.Info, "Sample fatal error message"); 
      } 
    } 

    六、配置文件

    logger.Trace()等等方法,只是在程序里发出日志消息,所以我们还需要在配置文件里设置哪些消息需要被记录下来,以及记录到什么位置(文本文件、数据库,等等)。

    1、在<targets>节点下,添加:

    <target name="logfile" xsi:type="File" fileName="file.txt" /> 

    代码定义了一个目标位置,用于将日志发送到file.txt文件。

    2、在<rules>节点下,添加:

    <logger name="*" minlevel="Info" writeTo="logfile" /> 

    这段代码将会将所有(name="*")级别为Info或者更高(包含Info, Warn, Error, Fatal)的日志转发到名为logfile的目标位置。

    七、多个目标位置

    <?xml version="1.0" encoding="utf-8" ?> 
    <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
                               
        <targets> 
            <target name="logfile" xsi:type="File" fileName="file.txt" /> 
            <target name="console" xsi:type="Console" /> 
        </targets> 
                               
        <rules> 
            <logger name="*" minlevel="Trace" writeTo="logfile" /> 
            <logger name="*" minlevel="Info" writeTo="console" /> 
        </rules> 
    </nlog> 

    八、特定Logger的路由

    可以在配置文件中指定只对某一个组件的日志进行记录。

    <?xml version="1.0" encoding="utf-8" ?> 
    <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
                            
        <targets> 
            <target name="logfile" xsi:type="File" fileName="file.txt" /> 
        </targets> 
                            
        <rules> 
            <logger name="SomeNamespace.Component.*" minlevel="Trace" writeTo="logfile" final="true" /> 
            <logger name="*" minlevel="Info" writeTo="logfile" /> 
        </rules> 
    </nlog>  

    这段代码表示只对以SomeNamespace.Component为前缀命名的组件的日志消息进行记录,final=“true”,表示这是最后一条日志规则,后续规则不会生效。

    九、包装器

    • ImpersonatingWrapper - Impersonates another user for the duration of the write.

    • AsyncWrapper - 提供异步、缓冲执行日志写入操作。 

    • FallbackGroup - 提供日志写入出错时的反馈。

    • FilteringWrapper - 基于条件过滤日志记录。 Filters log entries based on a condition.

    以异步操作为例:

    <?xml version="1.0" encoding="utf-8" ?> 
    <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
                       
        <targets> 
            <target name="asyncFile" xsi:type="AsyncWrapper"> 
                <target name="logfile" xsi:type="File" fileName="file.txt" /> 
            </target> 
        </targets> 
                       
        <rules> 
            <logger name="*" minlevel="Info" writeTo="asyncFile" /> 
        </rules> 
    </nlog>  

    十、布局

    设置日志的输出格式

    <target name="logfile" xsi:type="File" fileName="file.txt" layout="${date:format=yyyyMMddHHmmss} ${message}" /> 

    十一、在ASP.NET MVC 3中使用NLog记录用户操作

    需求:使用日志记录一个访问的UserName、Controller、Action、时间戳。

    1、增加名为UserTrackerLogAttribute的Filter

    public class UserTrackerLogAttribute : ActionFilterAttribute, IActionFilter 
    {        
    private static Logger logger = LogManager.GetCurrentClassLogger();
    public override void OnActionExecuted(ActionExecutedContext filterContext) { var actionDescriptor= filterContext.ActionDescriptor; string controllerName = actionDescriptor.ControllerDescriptor.ControllerName; string actionName = actionDescriptor.ActionName; string userName = filterContext.HttpContext.User.Identity.Name.ToString(); DateTime timeStamp = filterContext.HttpContext.Timestamp; string routeId=string.Empty; if (filterContext.RouteData.Values["id"] != null) { routeId = filterContext.RouteData.Values["id"].ToString(); } StringBuilder message = new StringBuilder(); message.Append("UserName="); message.Append(userName + "|"); message.Append("Controller="); message.Append(controllerName+"|"); message.Append("Action="); message.Append(actionName + "|"); message.Append("TimeStamp="); message.Append(timeStamp.ToString() + "|"); if (!string.IsNullOrEmpty(routeId)) { message.Append("RouteId="); message.Append(routeId); }

    logger.Log(message.ToString()); base.OnActionExecuted(filterContext); } }  

    2、在需要记录操作的Action中标记自定义的Filter

    [UserTrackerLog] 
    public ActionResult Index() 
    { 
        return View(); 
    }  

    3、配置文件沿用上文target的name属性值为“logfile”的配置。

    4、使用Legit Log Viewer可视化查看~/Logs/下的日志文件。

    十二、将日志记录到Sql Server

    1、创建数据表

    CREATE TABLE [dbo].[NLog_Error]( 
      [Id] [int] IDENTITY(1,1) NOT NULL, 
      [time_stamp] [datetime] NOT NULL, 
      [host] [nvarchar](max) NOT NULL,  
      [type] [nvarchar](50) NOT NULL,  
      [source] [nvarchar](50) NOT NULL,  
      [message] [nvarchar](max) NOT NULL,  
      [level] [nvarchar](50) NOT NULL,  
      [logger] [nvarchar](50) NOT NULL,  
      [stacktrace] [nvarchar](max) NOT NULL,  
      [allxml] [ntext] NOT NULL,  
     CONSTRAINT [PK_NLogError] PRIMARY KEY CLUSTERED  
    (  
        [Id] ASC 
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]  
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 
      GO  
    ALTER TABLE [dbo].[NLog_Error] ADD  CONSTRAINT [DF_NLogError_time_stamp]  DEFAULT (getdate()) FOR [time_stamp] 
    GO 

    2、配置Nlog.Config

    <targets>  
        <target xsi:type="Database" name="databaselog"> 
          <dbProvider>System.Data.SqlClient</dbProvider> 
          <connectionString>server=(local);Initial Catalog=PE.LayerArtitecture;Integrated Security=True;</connectionString> 
          <commandText> 
            insert into NLog_Error ([time_stamp],[level],[host],[type],[source],[logger],[message],[stacktrace],[allxml]) values(@time_stamp,@level,@host,@type,@source,@logger,@message,@stacktrace,@allxml); 
          </commandText> 
          <parameter name="@time_stamp" layout="${date}" /> 
          <parameter name="@level" layout="${level}" /> 
          <parameter name="@host" layout="${machinename}" /> 
          <parameter name="@type" layout="${exception:format=type}" /> 
          <parameter name="@source" layout="${callsite:className=true:fileName=false:includeSourcePath=false:methodName=false}" /> 
          <parameter name="@logger" layout="${logger}" /> 
          <parameter name="@message" layout="${message}" /> 
          <parameter name="@stacktrace" layout="${exception:stacktrace}" /> 
          <parameter name="@allxml" layout="${xml-encode}" /> 
        </target> 
      </targets> 
      <rules> 
        <!-- add your logging rules here --> 
        <logger minlevel="Info" name="*" writeTo="databaselog" /> 
      </rules> 
  • 相关阅读:
    mongodb删除指定字段
    nodejs地理坐标转换
    浅谈对腾讯云微信小程序解决方案服务端的理解(主要针对信道服务)
    利用Django进行微信支付接口的开发
    SpringBoot常用注解
    构建一个敏感词字典树
    Java异常统一处理
    [一天一个小知识]instanceof
    [总结]实现表格中对checkbox的操作
    小程序的数据绑定
  • 原文地址:https://www.cnblogs.com/bestzrz/p/2944105.html
Copyright © 2011-2022 走看看