Elmah 日志记录组件
http://www.cnblogs.com/jys509/p/4571298.html
简介
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。
使用方法
本篇来尝试Elmah在Asp.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.Demo\Static\Log)会出现一个XML文件:
3. 数据库存储方式
在数据可视化和管理上数据库依然是最理想的选择.这里采用SQlServer2008 版本测试.在构建Elmah支持SQLServer数据支持需要如下三个操作:
- a) 告诉ELMAH使用哪种数据库作为存储数据库;
- b) 告诉ELMAH如何连接到数据库;
- c) 指定的数据库里,要包含ELMAH需要的表、视图和存储过程等(嵌入式数据库不需要此过程)。
其中a和b步骤需要在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] GOALTER TABLE dbo.ELMAH_Error WITH NOCHECK ADD CONSTRAINT PK_ELMAH_Error PRIMARY KEY NONCLUSTERED(ErrorId) ON [PRIMARY] GOALTER TABLE dbo.ELMAH_Error ADD CONSTRAINT DF_ELMAH_Error_ErrorId DEFAULT (newid()) FOR [ErrorId] GOCREATE NONCLUSTERED INDEX IX_ELMAH_Error_App_Time_Seq ON dbo.ELMAH_Error ([Application] ASC,[TimeUtc] DESC,[Sequence] DESC ) ON [PRIMARY] GOSET QUOTED_IDENTIFIER ON GO SET ANSI_NULLS ON GOCREATE PROCEDURE dbo.ELMAH_GetErrorXml (@Application NVARCHAR(60),@ErrorId UNIQUEIDENTIFIER ) ASSET NOCOUNT ONSELECT AllXml FROM ELMAH_Error WHEREErrorId = @ErrorId ANDApplication = @ApplicationGO SET QUOTED_IDENTIFIER OFF GO SET ANSI_NULLS ON GOSET QUOTED_IDENTIFIER ON GO SET ANSI_NULLS ON GOCREATE PROCEDURE dbo.ELMAH_GetErrorsXml (@Application NVARCHAR(60),@PageIndex INT = 0,@PageSize INT = 15,@TotalCount INT OUTPUT ) AS SET NOCOUNT ONDECLARE @FirstTimeUTC DateTime DECLARE @FirstSequence int DECLARE @StartRow int DECLARE @StartRowIndex int-- Get the ID of the first error for the requested pageSET @StartRowIndex = @PageIndex * @PageSize + 1 SET ROWCOUNT @StartRowIndexSELECT @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 @PageSizeSELECT @TotalCount = COUNT(1) FROM ELMAH_Error WHERE Application = @ApplicationSELECT errorId, application,host, type,source,message,[user],statusCode, CONVERT(VARCHAR(50), TimeUtc, 126) + 'Z' time FROM ELMAH_Error error WHEREApplication = @Application AND TimeUTC <= @FirstTimeUTC AND Sequence <= @FirstSequence ORDER BYTimeUTC DESC, Sequence DESC FORXML AUTOGO SET QUOTED_IDENTIFIER OFF GO SET ANSI_NULLS ON GOSET QUOTED_IDENTIFIER ON GO SET ANSI_NULLS ON GOCREATE 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 ) ASSET NOCOUNT ONINSERT INTOELMAH_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> 节点下已经注释掉的相应配置即可。点击去下载
Elmah 日志记录组件相关推荐
- MVC使用 Elmah 日志记录组件
简介 ELMAH(Error Logging Modules and Handlers)错误日志记录模块和处理程序,是一种应用广泛的错误日志工具是完全可插拔.它可以动态添加到一个正在运行的ASP.NE ...
- 小巧的日志记录组件 - 开源研究系列文章
今天给大家带来一个小巧的日志记录组件LogHelper.这个组件是由Log4Net这个组件的由来而来的,不过只是写入.txt文本文件而已.如果能够对大家的项目有帮助那就更好了. 首先,打开.SLN解决 ...
- 日志记录组件[Log4net]详细介绍(转)
一 Log4net简介 Log4net是基于.net开发的一款非常著名的记录日志开源组件.他最早是2001年7月由NeoWorks Limited启动的项目,基本的框架源于另外的一个非常著名的姐妹组件 ...
- Apache日志记录组件Log4j出现反序列化漏洞 黑客可以执行任意代码 所有2.x版本均受影响...
开源的东西用的人多了,自然漏洞就多.Apache用于日志记录的组件Log4j使用非常灵活,在相当多的开源项目中都有使用,此次漏洞影响所有Apache Log4j 2.*系列版本: Apache Log ...
- html 日志记录组件,使用HTML自定义格式的Log4j.properties进行日志记录
我需要帮助编辑Apache Log4j文件的输出. 我正在使用html布局来保存创建的日志.这里是我的log4j.properties代码:使用HTML自定义格式的Log4j.properties进行 ...
- Nlog日志记录组件使用
前面做的项目都是用的log4或者用个文件类写入文件中记录日志,这个nlog用着很方便,同时也有net core的版本,一步一步操作吧 1,nuget 中找到nlog并下载安装,注意框架版本,也可以去官 ...
- Log4Net异常日志记录在asp.net mvc3.0的应用
前言 log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介.本文主要是简单的介绍如何在Visual ...
- 考虑题4所示的日志记录_基于Log4Net实现日志信息双向存储
1.引言 在上位机开发中,日志记录是必不可少的,我们可以通过日志记录做日志分析及错误追踪.初学者会采用txt文本写入来实现日志保存,但是文本写入不是线程安全,当存在多个线程同时写入日志时,就会出现一些 ...
- com+组件日志记录(log4net)
网上找了一个操作powershell的com+组件源码,配置好后,发现启用邮箱不稳定.因此在代码中用log4net加入异常日志记录.如下: private static readonly ILog l ...
最新文章
- Oracle 用户表空间的创建和授权
- python中isinstance(3、object)_Python中为什么推荐使用isinstance来进行类型判断?而不是type...
- 简述mysql的概念及作用_数据库 简答题
- centos7 卸载Qt5
- 10个程序员才懂的灯谜,你能猜对几个?
- 布局中常见的居中问题
- oracle rac实例切换,RAC+单实例DG的切换
- axure画扇形_axure实现粗略饼状图
- 涉及到各种场景-英语小记-最爱的一篇
- wifi(华硕天选2)找不到怎么办
- CPU卡PSAM卡 响应指令错误码
- html如何实现左右布局,前端中的左右布局实现
- STM32C8T6 流水灯的实现(库函数版)
- GIS技术在林业管理应用中有哪些功能?
- loaded the “XXXView“ nib but the view outlet was not set 解决方案
- HyperLedger超级账本智能合约部署问题
- QNAP 威联通磁盘分区探索与数据导出
- 工坊实验室 | CALCULATE 的嵌套使用
- 如果数据有质量,地球将成黑洞?
- RNDIS设备开发手记