2016年5月23日 星期一

ASP.NET MVC Elmah Dashboard - 查看 Elmah 存在 SQL Server 的記錄

無論是 ASP.NET WebFroms or MVC or WebApi,我都會在專案裡安裝使用 Elmah 來攔截紀錄例外錯誤,這個部落格裡也有很多篇文章在說明,Elmah 這套件真的是一個歷史悠久的工具,早在 2004 年就已經出現了,但是我真的很意外居然蠻多人是聽都沒有聽過,甚至有許多人是不懂為何要來攔截記錄錯誤(我就完全不懂這些人是如何知道網站發生了什麼例外錯誤,而且怎麼去做分析與修復?),有些團隊雖然沒有使用過 Elmah 而是選擇自己建立錯誤處理機制或是使用其他的錯誤攔截記錄機制,不管如何,例外錯誤的處理是不能夠掉以輕心的,問題往往都能夠從這些有被紀錄的 Exception 裡去被發現。

雖然 Elmah 有提供一個基本的記錄顯示介面,可以讓我們看到有哪些 Exception 被記錄下來,但長久下來要在一大多的 Exception Record 裡去找出問題或是作分析就會是一大難題,因為這個基本的顯示介面是相當陽春的,如果有將這些記錄存在 SQL Server 裡的話,還可以在 SSMS 裡去下 T-SQL 做資料查詢,但是要要查個 Exception 紀錄還要開啟 SSMS 也是蠻累人的,尤其是有些團隊的環境裡是不允許開發人員直接連接正式環境的 SQL Server,所以就無法使用 SSMS 去做查詢了。

如果有將 Elmah 所攔截的例外錯誤給存放到「SQL Server」的團隊,這邊向你們介紹一個簡單方便的套件「ASP.NET MVC ELMAH Dashboard

 


在正式進入介紹主題之前,先來回顧一下之前以 Elmah 為主題的文章:

ASP.NET MVC + ELMAH 監控並記錄你的網站錯誤資訊 1 基本安裝與介紹
ASP.NET MVC + ELMAH 監控並記錄你的網站錯誤資訊 2 修改 elmah 的預設瀏覽路徑
ASP.NET MVC + ELMAH 監控並記錄你的網站錯誤資訊 3 elmah 的信件通知設定與 favicon.icon 404 錯誤過濾
ASP.NET MVC + ELMAH 監控並記錄你的網站錯誤資訊 4 將 elmah 錯誤記錄儲存到 MS SQL Server 中
ELMAH - 自訂錯誤通知郵件的設定(於特定Exception)
ASP.NET MVC 使用Glimpse監測網站的一舉一動 3 - 結合ELMAH
ASP.NET MVC 3 使用 ELMAH 無法記錄正確 Http Status Code ? (此篇已收錄於 elmah 官網 Wiki - WebBase 單元中 http://code.google.com/p/elmah/wiki/WebBase
ASP.NET MVC 使用 Elmah 但不安裝 Elmah.MVC 的 location 修改
Elmah.MVC 2.0.0
ELMAH.MVC 2.0.1 - 可以自訂瀏覽路徑
ELMAH - 設定錯誤通知信件的主旨
ASP.NET MVC 與 Elmah.MVC 2.1.1 以及使用 Windows Azure SQL Database 的Schema 修改

另外還有在 2012-06-14 twMVC#2「攻略 ASP.NET MVC - 從無到有 與 效能剖析」這場研討會裡所另外準備「Log Reporting Dashboard」,這是將 Darren Weir 所創作的原始版本改寫為 ASP.NET MVC 3,在 twMVC 的 Github Repository 有將改寫後的原始碼分享出來,

https://github.com/twMVC/twMVC-2-2

雖然有改寫 Log Reporting Dashboard 並分享出來,但是在實際工作的專案裡有用的的次數卻是很少,很多無法使用的原因在於專案的 Log 不是存放在 SQL Server 裡。

上面雖然這麼說,但這篇要介紹的「ASP.NET MVC ELMAH Dashboard」這個套件的必要條件就是 Elmah 紀錄是存放到 SQL Server 裡,所以凡是存放到 Memory, XML 或其他儲存裝置的方式,就請不要在最後留言還問我存放到不是 SQL Server 的方式要怎麼使用這個套件,只能支援 SQL Server 喔!

 

ASP.NET MVC Elmah Dashboard

http://www.arebis.be/MvcElmahDashboard/

https://www.nuget.org/packages/Arebis.Web.Mvc.ElmahDashboard/

http://www.arebis.be/MvcElmahDashboard/MvcElmahDashboard_Readme.html

image

 

直接給大家看最終完成結果

MVC Elmah Dashboard 首頁

image

Logs

image

Log Details

image

image

Log 查詢

image

 

安裝說明

Step.1

這邊以一個新建立的 ASP.NET MVC 5 網站為例,然後安裝基本的 Elmah 套件

SNAGHTML1f6da08a

 

Step.2

因為是要將 Elmah 存放在 SQL Server 裡,這裡是使用 LocalDB,所以在專案裡新增 LocalDB 並且建立 Elmah 存放 Exception 記錄的 Table,

image

[ELMAH.Error] Table Create Schema

--~Changing index [dbo].[ELMAH_Error].PK_ELMAH_Error to a clustered index.  You may    want to pick a different index to cluster on.
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].    [ELMAH_Error]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[ELMAH_Error](
[ErrorId] [uniqueidentifier] NOT NULL,
[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] [nvarchar](max) NOT NULL,
CONSTRAINT [PK_ELMAH_Error] PRIMARY KEY CLUSTERED 
(
[ErrorId] ASC
)WITH (STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF)
)
END
 
IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[ELMAH_Error]') AND name = N'IX_ELMAH_Error_App_Time_Seq')
CREATE NONCLUSTERED INDEX [IX_ELMAH_Error_App_Time_Seq] ON [dbo].[ELMAH_Error] 
(
[Application] ASC,
[TimeUtc] DESC,
[Sequence] DESC
)WITH (STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE  = OFF)
GO
IF NOT EXISTS (SELECT * FROM dbo.sysobjects WHERE id =     OBJECT_ID(N'[DF_ELMAH_Error_ErrorId]') AND type = 'D')
BEGIN
ALTER TABLE [dbo].[ELMAH_Error] ADD  CONSTRAINT [DF_ELMAH_Error_ErrorId]  DEFAULT (newid()) FOR [ErrorId]
END
 
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ELMAH_GetErrorsXml]') AND type in (N'P', N'PC'))
BEGIN
EXEC dbo.sp_executesql @statement = N'
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
 
SELECT 
    @TotalCount = COUNT(1) 
FROM 
    [ELMAH_Error]
WHERE 
    [Application] = @Application
 
-- Get the ID of the first error for the requested page
 
SET @StartRowIndex = @PageIndex * @PageSize + 1
 
IF @StartRowIndex <= @TotalCount
BEGIN
 
    SET ROWCOUNT @StartRowIndex
 
    SELECT  
        @FirstTimeUTC = [TimeUtc],
        @FirstSequence = [Sequence]
    FROM 
        [ELMAH_Error]
    WHERE   
        [Application] = @Application
    ORDER BY 
        [TimeUtc] DESC, 
        [Sequence] DESC
 
END
ELSE
BEGIN
 
    SET @PageSize = 0
 
END
 
-- Now set the row count to the requested page size and get
-- all records below it for the pertaining application.
 
SET ROWCOUNT @PageSize
 
SELECT 
    errorId     = [ErrorId], 
    application = [Application],
    host        = [Host], 
    type        = [Type],
    source      = [Source],
    message     = [Message],
    [user]      = [User],
    statusCode  = [StatusCode], 
    time        = CONVERT(VARCHAR(50), [TimeUtc], 126) + ''Z''
FROM 
    [ELMAH_Error] error
WHERE
    [Application] = @Application
AND
    [TimeUtc] <= @FirstTimeUTC
AND 
    [Sequence] <= @FirstSequence
ORDER BY
    [TimeUtc] DESC, 
    [Sequence] DESC
FOR
    XML AUTO
 
' 
END
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ELMAH_GetErrorXml]') AND type in (N'P', N'PC'))
BEGIN
EXEC dbo.sp_executesql @statement = N'
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
 
' 
END
GO
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].    [ELMAH_LogError]') AND type in (N'P', N'PC'))
BEGIN
EXEC dbo.sp_executesql @statement = N'
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 NVARCHAR(MAX),
@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
    )
 
' 
END
GO

如果要增加 Dashboard 搜尋的速度,建議增加 ELMAH.Error 幾個欄位的索引

CREATE NONCLUSTERED INDEX [IX_ELMAH_Error_Application] ON [dbo].[ELMAH_Error] ([Application] ASC)
GO
CREATE NONCLUSTERED INDEX [IX_ELMAH_Error_Host] ON [dbo].[ELMAH_Error] ([Host] ASC)
GO
CREATE NONCLUSTERED INDEX [IX_ELMAH_Error_Type] ON [dbo].[ELMAH_Error] ([Type] ASC)
GO
CREATE NONCLUSTERED INDEX [IX_ELMAH_Error_Source] ON [dbo].[ELMAH_Error] ([Source] ASC)
GO
CREATE NONCLUSTERED INDEX [IX_ELMAH_Error_User] ON [dbo].[ELMAH_Error] ([User] ASC)
GO
CREATE NONCLUSTERED INDEX [IX_ELMAH_Error_TimeUtc] ON [dbo].[ELMAH_Error] ([TimeUtc] ASC)
GO
CREATE NONCLUSTERED INDEX [IX_ELMAH_Error_Sequence] ON [dbo].[ELMAH_Error] ([Sequence] ASC)
GO

 

Step.3

再來就是修改 Web.Config 裡面的 Elmah 設定,讓 Elmah 的記錄能夠儲存到 LocalDB 裡,

<;connectionStrings>
    <;add name="Elmah.Sql"
         connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFileName=|DataDirectory|\Sample.mdf;Integrated Security=True"
         providerName="System.Data.SqlClient" />;
</connectionStrings>    

image

 

Step.4

https://www.nuget.org/packages/Arebis.Web.Mvc.ElmahDashboard/

安裝「ASP.NET MVC Elmah Dashboard」套件

PM > Install-Package Arebis.Web.Mvc.ElmahDashboard

or

SNAGHTML1f8f03c8

安裝完畢後,會在 Visual Studio 開啟 ASP.NET MVC Elmah Dashboard 的 Readme 說明文件

image

因為這一篇文章只是做個簡單的介紹,並不會講到比較細的設定,例如 Security, 修改預設 Dashboard 路徑名稱等,一定要詳細把 Readme 給看仔細。

 

Step.5

安裝好套件之後,MVC Elmah Dashboard 會在 Web.Config 裡的 AppSettings 增加了一些設定,還需要做一些調整,

image

MvcElmahDashboardConnectionName,這個要改為 Elmah 存放到資料庫的連線名稱

MvcElmahDashboardCulture,這個看各地區的語言文化來決定,例如可以填入 en-us or zh-tw,會影響日期時間的顯示格式

MvcElmahDashboardLogCount,這個是設定在 Dashboard 首頁裡要顯示多少則最新的紀錄

以下是我修改後的設定內容

image

 

Step.6

到這邊還沒結束喔,因為 MVC Elmah Dashboard 是在 ASP.NET MVC 專案裡增加 Areas,而且在 MvcElmahDashboard 裡同樣也有一個 HomeController,如果在不修改 Route 設定的情況下執行網站,那麼就會遇到錯誤,

image

修改 ~App_Start/RouteConfig.cs,增加 namespaces 的條件約束

image

而 ~Areas/MvcElmahDashboard/MvcElmahDashboardAreaRegistration.cs 裡就已經有處理了

image

修改後再重新執行網站就可以正常了,而預設的情況下只要在網址根目錄後輸入 MvcElmahDashboard 就可以進入 MVC Elmah Dashbaord 的頁面,

image

 

到這邊為止就算是完成了,如果有些真的不是很清楚的話,可以仔細看看 Readme,例如讀取 MVC Elmah Dashboard 的權限設定

image

修改讀取 MVC Elmah Dashboard 的路徑設定

image

 

對了,在範例的說明過程中我並沒有另外再安裝 Elmah.MVC 喔,另外原本 Web.Config 的 Elmah 預設設定,我只有保留 elmah 區段的部分,其餘的都刪除。

image

 


以上就是給各位介紹的 ASP.NET MVC Elmah Dashboard,如果是把 Elmah 記錄存放在 SQL Server 的話,不妨就考慮使用。

 

參考連結

MVC ELMAH Dashboard
http://www.arebis.be/MvcElmahDashboard/

MVC ELMAH Dashboard Readme
http://www.arebis.be/MvcElmahDashboard/MvcElmahDashboard_Readme.html

NuGet Gallery| ASP.NET MVC ELMAH Dashboard 1.0.0
https://www.nuget.org/packages/Arebis.Web.Mvc.ElmahDashboard/

Configuring ELMAH to use SQL Server ~ andyfrench.info
http://www.andyfrench.info/2014/07/configuring-elmah-to-use-sql-server.html

 

延伸閱讀

mrkt 的程式學習筆記: 系統記錄與效能監測
http://kevintsengtw.blogspot.tw/p/blog-page_12.html

 

以上

2 則留言:

  1. 你好,照著教學在本機建了一個專案,發現用 IIS Express 跑錯誤,可以成功記錄到錯誤到 DB;但是如果改成 Local IIS 執行的便無法攔截錯誤記錄到 DB,是否可以請教這有可能是什麼原因造成的?

    回覆刪除
    回覆
    1. 你所使用的 DB 是那一種呢?
      LocalDB SqlExpress or 一般的 Sql Server ?
      三種是有差異的,你可以先去了解這些 db 的不同和使用限制,你就會知道答案

      刪除

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。

最近的留言