• ElMAH(ASP.NET错误日志记录与通知)系列文章基础应用篇


    原文地址:http://www.cnblogs.com/lerit/archive/2011/04/19/2020565.html

    最近在研究几个ASP.NET的开源项目时,发现都在使用ELMAH来作为记录整个应用程序的错误日志,于是拿来小研究了一下,在这里和各位分享一下,如果有使用过的,请多指教。

        对于ELMAH,将用三篇系列文章来介绍:

    •     概念篇
    •     基本应用篇
    •     高级应用篇

       基本应用篇

    1.ELMAH初体验

    先来快速体验一下ELMAH应用于一个项目的最少操作是多么简单吧。(以开发环境下的ASP.NET程序为例)

    步骤1:用VS2010开发平台打开需要添加ELMAH程序的ASP.NET项目。使用NuGet(一个用于维护.NET FrameWork常用类库的VS2010扩展,当然ELMAH也在其中,NuGet的介绍及其安装请看参考文章1),添加ELMAH。即:

    菜单选择:工具-Library Package Manager-Add Library Package Reference…,打开添加类库界面。

    op1

    在线搜索ELMAH,点击install按钮,则ELMAH的配置工作自动完成。

    op2

    步骤2:其实上面一个步骤,就完成了所有配置了。现在,来试试效果吧:

    首先制造一个报错。任选一个页面(这里假设为index.aspx),我在Page_Onload事件中加了一句:

     protected void Page_Load(object sender, EventArgs e)
        {
            int a = Convert.ToInt16("w");
        }

    显然在加载这个页面时,会报错的。运行此页面(这里地址是http://localhost:52450/MyTestWebProject/Default.aspx),如果系统没有别的配置,应该看到我们最常见的黄颜色报错界面。

    error1

    现在来看看ELMAH记录这个错误的情况,输入:http://localhost:52450/MyTestWebProject/elmah.axd即可看到记录下的错误信息。

    error2

    以上操作也可以参考liping13599168老兄的文章,图文并茂,比较详细。

    就是这么简单,ELMAH在后台记录了错误信息,并为我们提供了查询错误日志信息的界面,只需要简单的操作,就完成了基本的需求。当然,ELMAH还提供了丰富的功能,从而满足不同的需求,之后将会介绍。

    上述使用NuGet来配置ELMAH,对用户来说是透明的,下面来看看他具体都干了写什么:

    (1)将Elmah.dll复制到程序的根目录的Bin文件夹下(若没有自动创建);

    (2)在web.config中configuration、httpHandlers和httpModules中增加了如下内容(斜体部分):

    <configuration>
     <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>
    
    <httpHandlers>
        <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
    </httpHandlers>
       
    <httpModules>
        <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
    </httpModules> 

    就这些,他已经可以实现ELMAH的基本功能了。因此,如果对于不想使用NuGet自动配置,或者在生产环境下已经运行的程序来说,按照如上两个步骤,依然可以手动配置。

    现在来回顾一下上一篇文章吧,结合这个例子,从而更形象的理解它的工作机制。

    当请求的页面报错后,就如上面所示,将会把那个报错的黄颜色界面返回给用户,在返回时,先被httpModules中的名为ErrorLog的模块截获,这一模块将错误信息记录起来;当需要查看日志信息时(如上所示访问根目录下elmah.axd文件),这个请求发给IIS后,先被httpHandlers捕获,并交给了其中专门处理elmah.axd的处理程序,这个处理程序就把那个错误日志界面展示给用户了。

    至于web.config中新增加的<sectionGroup name="elmah"> 以及其中的信息,主要是实现更多丰富功能的配置项,这将会是本文余下部分以及下一章的内容。这里只简单说一下,以便有个印象:(实际上NuGet还少加了一个,这里给出完整版)

    <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"/>
    <section name="errorTweet" requirePermission="false" type="Elmah.ErrorTweetSectionHandler, Elmah"/>
    
    </sectionGroup> 
    
    

    其中security用于配置访问日志信息的权限,errorLog用于配置记录日志的存储方式(数据库、文件还是内存等),errorMail和errorTweet分别用于配置发生错误时,以邮件或Twitter方式通知管理员的操作,errorFilter用于配置记录日志时,过滤错误信息的类型。由于每一个都对应一个功能,因此可以根据需要只写其中的几个也是没问题的。另外,每一条都类似于一个声明,告诉ELMAH,用户要实现某几个功能,至于如何实现,那么还需要再web.config的其他地方告诉具体的实现方式,下面将例子时候就清楚了。本章下面只讲errorLog,其他内容见下一篇。

    2.配置存储方式

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

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

    (1)数据库存储方式

    即将发布的v1.2正式版本的ELMAH支持的数据库有:

    要以数据库作为日志的存储方式,应该完成三件事:

    a) 告诉ELMAH使用哪种数据库作为存储数据库;

    b) 告诉ELMAH如何连接到数据库;

    c) 指定的数据库里,要包含ELMAH需要的表、视图和存储过程等(嵌入式数据库不需要此过程)。

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

    这里以SQL Server数据库为例,其它数据库的配置类似,不再赘述。

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

    <configSections>  
    <sectionGroup name="elmah">
    <!--告诉elmah,我要记录错误日志-->
    <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />   
    </sectionGroup>
      </configSections>
      <elmah>
    <!-- 告诉elmah,我要采用sqlserver来记录我的日志,连接那个数据库的字符串名为myconnectionString。-->
       <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="myconnectionString" />
    <!--
    实际上,当使用asp.net 2.0及以上版本时,上面的这种方式是没问题的,如果使用asp.net 1.x版本,应该使用:
    <errorLog type="Elmah.SqlErrorLog, Elmah" connectionString="Data Source=.;Initial Catalog=MVCMUSICSTORE;Integrated Security=True" /> 
    也就是说,这种方式把下面那个连接字符串直接写在这里了,就不需要下面的那个配置了。
    -->
      </elmah>
      <connectionStrings>
    <!-- 这就是我们用于连接sqlserver数据库的连接字符串。-->
        <add name="myconnectionString" connectionString="Data Source=.;Initial Catalog=MVCMUSICSTORE;Integrated Security=True"/>
      </connectionStrings>

    没什么好说,都注释清楚了,这一配置告诉了采用哪种数据库来记录,以及如何连接数据库。

    再来看看如何实现c过程,也就是创建一些对象。数据库要能记录日志,一定需要一些表的,当然可能还有辅助的视图、存储过程等。可惜,ELMAH不能自动创建这些对象,我们需要手动添加。只需要在数据库中执行如下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

    这样,就完成了配置完毕。采用数据记录日志,需要注意三点:

    • 注意asp.net版本的不同,对于配置的影响;
    • 不同关系型数据库的sql语句可能略有不同,应适当修改;
    • 嵌入式数据库无需配置第三步骤(c);
    • 不同数据库的连接字符串有所不同;
    • 嵌入式数据库(目前支持SQLite和VistaDB),如果配置中指定的数据文件不存在,则ELMAH会自动创建(权限允许时);但是,关系型数据库,如果不存在,是不会自动创建的。

    其他数据库的配置也是类似的,就不多说了。完全可以看参考文章2,介绍了每种连接方式。

    (2)文件存储方式

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

    <configSections>  
    <sectionGroup name="elmah">
    <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />   
    </sectionGroup>
      </configSections>
      <elmah>
    <!--与数据库方式相比,实际上只有这一句就行了,其中logPath用于指定记录日志的文件夹位置-->
     <errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="~/Log/" />
      </elmah>

    这里,logPath用于指定存储日志xml文件的位置。如果路径指定位置的文件夹不存在,ELMAH是不会自动创建的,另外,并且应该保证asp.net对此目录具有读写权限。

    (3)内存存储方式

    在上面的ELMAH初体验一节中,实际上已经介绍过了。只要不指定任何存储方式,则默认就是内存存储方式了。当然,也可以显式的指定为内存存储方式。

    <configSections>  
    <sectionGroup name="elmah">
    <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />   
    </sectionGroup>
      </configSections>
      <elmah>
        <errorLog type="Elmah.MemoryErrorLog, Elmah"/>
      </elmah>

    但这种方式应该只用于测试阶段,运行于生产环境中的系统,不应该使用此方式,这主要是基于此种方式的工作原理导致的。

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

    asp.net development server

    简单总结一下各种方式:

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

    3.错误日志记录查看

    按照如上步骤,日志已经被记录到相应介质中了。那么接下来就是如何查询这些日志信息。

    实际上第一节中,就简单介绍了查询界面(第四张图),是在没啥可讲的,点点就知道了。这里还是介绍一下吧。

    LogQuery

    四个红框,将这个页面分为四个区域:

    区域1,菜单区,包括五个内容:

    • RSS FEED 也就是rss种子,也就是订阅这一日志的rss连接。
    • RSS DIGEST 也是rss种子,但是显示的是最近15天的日志信息。
    • DOWNLOAD LOG 下载日志,以cvs格式,导出日志为文件。
    • HELP 帮助,连接到ELMAH的主页。
    • ABOUT 关于,点击后,显示当前ELMAH的版本,源代码信息,以及一个检查是否为最新版的按钮。

    区域2,分页,选择相应数字,即可分页显示日志。

    区域3,内容区,分为7列:

    • Host 导致报错信息的访问主机名。
    • Code 错误的HTTP状态码。
    • Type 错误类型。
    • Error 错误的信息。其中再次点击Details,可以详细查看报错信息,与本文图3类似。
    • User 导致报错信息的访问主机的用户。
    • Date 发生错误的日期。
    • Time 发生错误的时间。

    区域4,版本与版权声明信息等。

    注:

    从这一篇的介绍可以看出,ELMAH的功能还是很多的,不过也存在一些问题需要解决:

    • ELMAH配置的数据库连接字符串无法加密,或者无法指定为加密了的connectionstring;
    • ELMAH不能在指定的关系型数据库中自动创建相应对象;
    • 日志内容是增长的,但ELMAH没有提供清空日志的功能;
    • 查询功能比较薄弱,不能提供过滤条件。

    参考文章:

    1. 《ASP.NET MVC 3.0学习系列文章—NuGet and ASP.NET MVC 3.0》

    2.《ELMAH的web.config详细配置(v1.1)》

    3. 《数据库连接参数 网址》

  • 相关阅读:
    web版仿微信聊天界面|h5仿微信电脑端案例开发
    h5仿微信聊天(高仿版)、微信聊天表情|对话框|编辑器
    原生wcPop.js消息提示框(移动端)、内含仿微信弹窗效果
    旅行app(游记、攻略、私人定制) | 顺便游旅行H5移动端实例
    【h5+c3】web前端实战项目、快装webapp手机案例源码
    h5区块链项目实战
    css3波纹特效、H5实现动态波浪
    H5移动端项目案例、web手机微商城实战开发
    HTML5仿微信聊天界面、微信朋友圈实例
    Android 给服务器发送网络请求
  • 原文地址:https://www.cnblogs.com/alphaqiu/p/2375464.html
Copyright © 2020-2023  润新知