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.Demo\Static\Log)會出現一個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> 節點下已經注釋掉的相應配置即可。點擊去下載

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM