zoukankan      html  css  js  c++  java
  • MVC使用 Elmah 日志记录组件

    简介

    ELMAH(Error Logging Modules and Handlers)错误日志记录模块和处理程序,是一种应用广泛的错误日志工具是完全可插拔。它可以动态添加到一个正在运行的ASP.NET Web应用程序,甚至是一台机器上的所有ASP.NET Web应用程序,而无需重新编译或重新部署。 

    ELMAH既支持ASP.NET Web Forms 又支持 ASP.NET MVC。你可以对ELMAH进行配置来存储各种不同的错误(XML文件,事件日志,Access数据库,SQL数据库,Oracle数据库,或者计算机 RAM。)你还可以让ELMAH在错误发生的时候,把错误信息email给你。

    在默认情况下,在一个已经安装ELMAH的网站中,你可以通过请求的elmah.axd页面的方式来访问ELMAH。

    使用方法

    本篇来尝试ElmahAsp.net MVC 5使用.

    第一步:安装布署

    首先Build 空的Asp.net MVC 5 Project:

    添加Elmah引用:

    Elmah组建已经配置成功.其实这个过程做了两件事:

    • A:Elmah.dll复制到程序的根目录的Bin文件夹下.并当前项目的引用.
    • B:向项目根目录下Web.Config文件添加如下内容

    在webConfig文件中添加如下内容:

      <configSections>
        <sectionGroup name="elmah">
          <section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
          <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
          <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
          <section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
        </sectionGroup>
      </configSections>
    
    <elmah>
        <!--
            See http://code.google.com/p/elmah/wiki/SecuringErrorLogPages for 
            more information on remote access and securing ELMAH.
        -->
        <security allowRemoteAccess="false" />
      </elmah>
      <location path="elmah.axd" inheritInChildApplications="false">
        <system.web>
          <httpHandlers>
            <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
          </httpHandlers>
          <!-- 
            See http://code.google.com/p/elmah/wiki/SecuringErrorLogPages for 
            more information on using ASP.NET authorization securing ELMAH.
    
          <authorization>
            <allow roles="admin" />
            <deny users="*" />  
          </authorization>
          -->
        </system.web>
        <system.webServer>
          <handlers>
            <add name="ELMAH" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" preCondition="integratedMode" />
          </handlers>
        </system.webServer>
      </location>

    第二步:测试使用

    HomeController.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    
    namespace Elmah.Demo.Controllers
    {
        public class HomeController : Controller
        {
            //
            // GET: /Home/
            public ActionResult Index()
            {
                return View();
            }
    
            [HttpPost]
            public ActionResult GenerateError(string error)
            {
                throw new ApplicationException(error);
            }
    
        }
    }

    index.cshtml

    @{
        Layout = null;
        ViewBag.Title = "Index";
    }
    
    <div>
        <input type="text" id="ErrorMsg" />
        <button id="GenerateError">生成错误日志</button>
        <a href="/elmah.axd" target="_blank">在elmah中查看错误日志</a>
    </div>
    
    
    <script src="~/Scripts/jquery-1.10.2.js"></script>
    <script type="text/javascript">
        $("#GenerateError").click(function () {
            $.post("/Home/GenerateError?error=" + $("#ErrorMsg").val());
        });
    </script>

     运行效果如下:

    如果不是Post方式,会报黄页,如:

    来看看Elmah是否记录本次执行过程中出现的异常:

    可以看到Elmah已经如期的扑捉到当前应用程序的异常.ELMAH在后台记录了错误信息,并为我们提供了查询错误日志信息的界面,只需要简单的操作,就完成了基本的需求.

    存储方式

    有人可能会问,上面的自动配置中,并没有指定存储日志的方式啊(当然这里还没介绍如何配置,但是从上面配置中,似乎也看不到有哪里指定了存储方 式),那这些数据存储在哪里了呢?答案是,NuGet安装ELMAH后,它是没有指定任何存储方式。而ELMAH认为,如果没有指定存储方式,那么就采用 默认的内存存储方式(也可以显式的指定)。但是这种存储方式只能作为调试阶段使用,生产环境下不应使用此方式,具体的缺点请看下面对内存存储方式的介绍。

    接下来就具体介绍各种存储方式,分别以数据库存储、文件存储和内存存储为例,需要强调一点,ELMAH目前只支持一下三种方式中的任意一种,不支持同时采用多种记录方式。(想必也没这个必要)

    1.内存存储方式

    内存存储,顾名思义,将日志记录于操作系统分配给应用程序的内存中。应用程序的内存是与应用程序域相关的,这可以保证每个应用程序只能获取和记录属于自己 的日志信息。但是,一旦应用程序重启,之前记录的信息将会消失。最简单的例子,如果你用这种方式调试呢,默认是用ASP.NET Development Server作为web服务器,如果这时停止此服务器,则就满足上述条件了(如下图)。另外,断电,发布后IIS的重启等问题,都会导致记录的信息丢失。 因此,这种方式只能用于测试用。

    其实Elmah处理原理.当我们请求页面报错时.在返回黄页错误时首先被 httpModules中名为ErrorLog模块进行拦截. 该模块将本次请求出错的信息保存起来.-默认是放置在内存中.便于即时调试.但用户输入elmah.axd要查看日志信息时. 首先httpHandlers捕获到该请求.并交给专门处理elmah.axd的处理程序.该模块把错误日志View返回给用户.可见Elmah核心技术 还是基于HttpModules和HttpHandlers来实现的.

    2.文件存储方式

     文件存储实际上ELMAH提供了xml文件的存储方式,每一个报错日志信息生成一个xml文件。配置相当简单:

      <elmah>
        <!--
            See http://code.google.com/p/elmah/wiki/SecuringErrorLogPages for 
            more information on remote access and securing ELMAH.
        -->
        <security allowRemoteAccess="false" />
        <!--只有这一句就行了,其中logPath用于指定记录日志的文件夹位置-->
        <errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="~/Static/Log/" />
      </elmah>

    该配置必需确认LogPath路径目录是完整存在的.测试会发现在本地文件中(Elmah.DemoStaticLog)会出现一个XML文件:

    3. 数据库存储方式

     在数据可视化和管理上数据库依然是最理想的选择.这里采用SQlServer2008 版本测试.在构建Elmah支持SQLServer数据支持需要如下三个操作:

    • a) 告诉ELMAH使用哪种数据库作为存储数据库;
    • b) 告诉ELMAH如何连接到数据库;
    • c) 指定的数据库里,要包含ELMAH需要的表、视图和存储过程等(嵌入式数据库不需要此过程)。

    其中ab步骤需要在web.config中指定,c则需要在数据库中添加相关对象。

    web.config配置如下(httpModules以及httpHandlers就不贴了,这里只给出ELMAH记录日志于sqlserver数据库的配置):

      <connectionStrings>
        <add name="elmah-sqlserver" connectionString="server=.;database=MvcTest;user id=sa;password=111111@a" providerName="System.Data.SqlClient" />
      </connectionStrings>
    
      <elmah>
        <!--
            See http://code.google.com/p/elmah/wiki/SecuringErrorLogPages for 
            more information on remote access and securing ELMAH.
        -->
        <security allowRemoteAccess="false" />
        <!--只有这一句就行了,其中logPath用于指定记录日志的文件夹位置-->
        <!--<errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="~/Static/Log/" />-->
        <!-- 告诉elmah,我要采用sqlserver来记录我的日志,连接那个数据库的字符串名为myconnectionString。-->
        <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="elmah-sqlserver" />
      </elmah>

    创建数据库,在该数据执行如下SQL语句.请参考官方的连接.

    Elmah SQL Server Script File:http://code.google.com/p/elmah/source/browse/src/Elmah/SQLServer.sql

    脚本:

    CREATE TABLE dbo.ELMAH_Error
    (
        ErrorId     UNIQUEIDENTIFIER NOT NULL,
        Application NVARCHAR(60) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
        Host        NVARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
        Type        NVARCHAR(100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
        Source      NVARCHAR(60) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
        Message     NVARCHAR(500) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
        [User]      NVARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
        StatusCode  INT NOT NULL,
        TimeUtc     DATETIME NOT NULL,
        Sequence    INT IDENTITY (1, 1) NOT NULL,
        AllXml      NTEXT COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
    GO
    
    ALTER TABLE dbo.ELMAH_Error WITH NOCHECK ADD 
        CONSTRAINT PK_ELMAH_Error PRIMARY KEY NONCLUSTERED
        (
            ErrorId
        )  ON [PRIMARY] 
    GO
    
    ALTER TABLE dbo.ELMAH_Error ADD 
        CONSTRAINT DF_ELMAH_Error_ErrorId DEFAULT (newid()) FOR [ErrorId]
    GO
    
    CREATE NONCLUSTERED INDEX IX_ELMAH_Error_App_Time_Seq ON dbo.ELMAH_Error
    (
        [Application] ASC,
        [TimeUtc] DESC,
        [Sequence] DESC
    ) ON [PRIMARY]
    GO
    
    SET QUOTED_IDENTIFIER ON 
    GO
    SET ANSI_NULLS ON 
    GO
    
    CREATE PROCEDURE dbo.ELMAH_GetErrorXml
    (
        @Application NVARCHAR(60),
        @ErrorId UNIQUEIDENTIFIER
    )
    AS
    
    SET NOCOUNT ON
    
    SELECT 
        AllXml
    FROM 
        ELMAH_Error
    WHERE
        ErrorId = @ErrorId
    AND
        Application = @Application
    
    
    
    GO
    SET QUOTED_IDENTIFIER OFF 
    GO
    SET ANSI_NULLS ON 
    GO
    
    SET QUOTED_IDENTIFIER ON 
    GO
    SET ANSI_NULLS ON 
    GO
    
    CREATE PROCEDURE dbo.ELMAH_GetErrorsXml
    (
        @Application NVARCHAR(60),
        @PageIndex INT = 0,
        @PageSize INT = 15,
        @TotalCount INT OUTPUT
    )
    AS 
    
    SET NOCOUNT ON
    
    DECLARE @FirstTimeUTC DateTime
    DECLARE @FirstSequence int
    DECLARE @StartRow int
    DECLARE @StartRowIndex int
    
    -- Get the ID of the first error for the requested page
    
    SET @StartRowIndex = @PageIndex * @PageSize + 1
    SET ROWCOUNT @StartRowIndex
    
    SELECT  
        @FirstTimeUTC = TimeUTC,
        @FirstSequence = Sequence
    FROM 
        ELMAH_Error
    WHERE   
        Application = @Application
    ORDER BY 
        TimeUTC DESC, 
        Sequence DESC
    
    -- Now set the row count to the requested page size and get
    -- all records below it for the pertaining application.
    
    SET ROWCOUNT @PageSize
    
    SELECT 
        @TotalCount = COUNT(1) 
    FROM 
        ELMAH_Error
    WHERE 
        Application = @Application
    
    SELECT 
        errorId, 
        application,
        host, 
        type,
        source,
        message,
        [user],
        statusCode, 
        CONVERT(VARCHAR(50), TimeUtc, 126) + 'Z' time
    FROM 
        ELMAH_Error error
    WHERE
        Application = @Application
    AND 
        TimeUTC <= @FirstTimeUTC
    AND 
        Sequence <= @FirstSequence
    ORDER BY
        TimeUTC DESC, 
        Sequence DESC
    FOR
        XML AUTO
    
    GO
    SET QUOTED_IDENTIFIER OFF 
    GO
    SET ANSI_NULLS ON 
    GO
    
    SET QUOTED_IDENTIFIER ON 
    GO
    SET ANSI_NULLS ON 
    GO
    
    CREATE PROCEDURE dbo.ELMAH_LogError
    (
        @ErrorId UNIQUEIDENTIFIER,
        @Application NVARCHAR(60),
        @Host NVARCHAR(30),
        @Type NVARCHAR(100),
        @Source NVARCHAR(60),
        @Message NVARCHAR(500),
        @User NVARCHAR(50),
        @AllXml NTEXT,
        @StatusCode INT,
        @TimeUtc DATETIME
    )
    AS
    
    SET NOCOUNT ON
    
    INSERT
    INTO
        ELMAH_Error
        (
            ErrorId,
            Application,
            Host,
            Type,
            Source,
            Message,
            [User],
            AllXml,
            StatusCode,
            TimeUtc
        )
    VALUES
        (
            @ErrorId,
            @Application,
            @Host,
            @Type,
            @Source,
            @Message,
            @User,
            @AllXml,
            @StatusCode,
            @TimeUtc
        )
    
    GO
    SET QUOTED_IDENTIFIER OFF 
    GO
    SET ANSI_NULLS ON 
    GO

    执行sQL语句完成后会在当前数据库看到表:

     当再次运行应用程序.在Throw ArgumentNullException时查询数据库:

     简单总结一下各种方式:

    • 数据库存储方式,配置相对麻烦,但对于大规模日志的记录,效率最好; 
    • 文件存储方式,配置相对简单,每日志一个文件,当数据量很大后,可能会导致巨量文件带来的效率问题; 
    • 内存存储,配置最简单,但是鉴于以上原因,不应使用于生产环境。

    补充

    在使用Elmah过程发一下一些特点.这里需要说明一下.

    Elmah是通过Http Modules 和Http Handler来记录和展示程序捕获的异常. 但是如果你在应用程序中添加异常处理模块.Try-Catch Elmah是无法记录到的.或是在Catch后在Throw出来. 在整个应用程序异常链上. 只有最终的异常抛给了Asp.net运行时Elmah组件才能捕获到并记录.

    有很多人认为加入Elmah组件后能够处理应用异常.其实本质上Elmah本质上是一个日志记录工具.并没有处理异常的能力.所以如果异常发生.不会改变原来应用程序给用户体验.依然还会出现黄色页面.

    在官方Note明确提到一个例外:

    ELMAH捕获异常是基于HttpApplication对象的Error事件。

    如果软件项目中的一些处理导致了HttpApplication事件无法被触发(比如在发生异常后,还没来得及执行Application_Error,就执行了Server.ClearError()方法,

    会阻止Error事件的触发,再比如,如果一个异常被try-catch捕获到,并且没有再次throw,那么异常也是不会最终触发Error事件)

     日志记录工具还是不少的,比如著名的Log4net。Log4Net包含了主要有四种重要的组件,分别是Logge, Repository, Appender以及 Layout.功能强大.可以自定义日志输出级别.具体操作可以参考我的另一遍文章:

     Log4net配置与使用

    提供源码,源码默认是内存存储方式,需要改为文件或者数据库,请更改<elmah> 节点下已经注释掉的相应配置即可。点击去下载

  • 相关阅读:
    CustomDrawableTextView
    Snippet: align a TextView around an image
    How to import library ?
    Gradle自定义你的BuildConfig
    使用adb shell dumpsys检测Android的Activity任务栈
    Activity intent经常使用的 FLAG
    使用 ContentProviderOperation 来提升性能
    幻方算法
    自己制作的粉碎机批处理程序
    Ubuntu 16.10 server 相关
  • 原文地址:https://www.cnblogs.com/jys509/p/4571298.html
Copyright © 2011-2022 走看看