前面幾篇文章有關 ELMAH 的文章都是把錯誤訊息記錄在「~/App_Data/Elmah.Errors」下,然後一個錯誤就是一個 XML 檔案,這樣做的原因是可以避免因為資料庫無法連線時而造成錯誤訊息無法記錄的意外,而本篇文章將會說明如何將 ELMAH 的錯誤訊息的儲存媒體改為使用 SQL Server。
如果說要做資料分析的話,其實也可以把錯誤訊息給匯出,匯出的格式為CSV檔案,
用Excel開啟errorlog.csv查看內容,
其實也是可以用這個方式來篩選資料出來,但一旦還是有人會覺得這樣的方式太不直接,所以希望把錯誤訊息記錄到SQL Server之中,可以使用SSMS來去篩選資料,而ELMAH置換記錄媒體的方式也相當簡單,不需要去更動到程式的部份,只需要去修改Web.Config就可以了。
首先我會建議,像這樣的錯誤訊息記錄,最好是要與網站所使用的資料庫是分開的,在同一個Server是可以,但是DB絕對要分開,讓系統使用的功能與網站的Model切分開來,不要混在一起,如果可以的話,錯誤訊息記錄也最好是放至於另外一台SQL Server,必須要將各種可能發生錯誤導致無法將錯誤訊息完整記錄的機率降到最低,讓程式開發人員、維護人員能儘量掌握完整的資訊。
官網提供的SQL Script
我們先到 Elmah 的官網,去找官網所提供的 SQL Script
SQLServer.sql :http://elmah.googlecode.com/svn/trunk/src/Elmah/SQLServer.sql
/*
ELMAH - Error Logging Modules and Handlers for ASP.NET
Copyright (c) 2004-9 Atif Aziz. All rights reserved.
Author(s):
Atif Aziz, http://www.raboof.com
Phil Haacked, http://haacked.com
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
-- ELMAH DDL script for Microsoft SQL Server 2000 or later.
-- $Id$
DECLARE @DBCompatibilityLevel INT
DECLARE @DBCompatibilityLevelMajor INT
DECLARE @DBCompatibilityLevelMinor INT
SELECT
@DBCompatibilityLevel = cmptlevel
FROM
master.dbo.sysdatabases
WHERE
name = DB_NAME()
IF @DBCompatibilityLevel <> 90
BEGIN
SELECT @DBCompatibilityLevelMajor = @DBCompatibilityLevel / 10,
@DBCompatibilityLevelMinor = @DBCompatibilityLevel % 10
PRINT N'
===========================================================================
WARNING!
---------------------------------------------------------------------------
This script is designed for Microsoft SQL Server 2005 (9.0) but your
database is set up for compatibility with version '
+ CAST(@DBCompatibilityLevelMajor AS NVARCHAR(80))
+ N'.'
+ CAST(@DBCompatibilityLevelMinor AS NVARCHAR(80))
+ N'. Although
the script should work with later versions of Microsoft SQL Server,
you can ensure compatibility by executing the following statement:
ALTER DATABASE ['
+ DB_NAME()
+ N']
SET COMPATIBILITY_LEVEL = 90
If you are hosting ELMAH in the same database as your application
database and do not wish to change the compatibility option then you
should create a separate database to host ELMAH where you can set the
compatibility level more freely.
If you continue with the current setup, please report any compatibility
issues you encounter over at:
http://code.google.com/p/elmah/issues/list
===========================================================================
'
END
GO
/* ------------------------------------------------------------------------
TABLES
------------------------------------------------------------------------ */
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] NVARCHAR(MAX) 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
/* ------------------------------------------------------------------------
STORED PROCEDURES
------------------------------------------------------------------------ */
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
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
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 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
)
GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO
這一段SQL Script會建立一個Table與三個Stored Procedure:
接下來就是在Web.Config中的connectionStrings區段再去新增connectionStrings:
<connectionStrings><add name="NorthwindEntities" connectionString="metadata=res://*/Northwind.csdl|res://*/Northwind.ssdl|res://*/Northwind.msl;provider=System.Data.SqlClient;provider connection string="data source=你的Data-Source;initial catalog=Northwind;persist security info=True;user id=登入帳號;password=登入密碼;multipleactiveresultsets=True;App=EntityFramework"" providerName="System.Data.EntityClient" /><add name="Elmah.Sql" connectionString="data source=你的Data-Source;initial catalog=ElmahError;persist security info=True;user id=登入帳號;password=登入密碼;Trusted_Connection=True" /></connectionStrings>
要記住這個connectionString的名稱「Elmah.Sql」
修改Web.Config
然後就是修改Web.Config的Elmah區段,
<elmah><!--<errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="~/App_Data/Elmah.Errors" />-->
<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="Elmah.Sql" /><security allowRemoteAccess="yes" />
原本使用errorLog為XmlFileErrorLog的資料給註解起來,然後增加Elmah.SqlErrorLog的設定,而connectionStringName就是之前所增加的連結字串名稱,修改好之後,重新建置網站,然後執行網站並且執行一個錯誤,接這就是看看資料庫ElmahError有沒有確實記錄錯誤訊息?
可以看到確實有將錯誤訊息給記錄到資料庫之中,ELmah更換儲存媒體並不會很麻煩,應該說是相當無痛且簡單,完全不會有任何複雜的操作。
2013-09-12 補充:
這邊會建議各位如果可以透過 NuGet 安裝 ELMAH與 ELMAH on MS SQLServer,
安裝 ELMAH on MS SQL Server 後,在專案有新增 App_Readme 目錄,目錄下有「Elmah.SqlServer.sql」檔案,
這個 Elmah.SqlServer.sql 內容與官網所提供的 SQL Script 大致相同,不過我會建議使用官網所提供的 SQL Script,部分欄位型別有更換比較適當的型別,例如使用 NVARCHAR(MAX) 而不是使用 NTEXT 等。
延伸閱讀:
Elmah - Storing errors in SQL Server
Elmah - OracleErrorLog (Using ELMAH with Oracle)
以上
sql file response 404,
回覆刪除update link:
http://elmah.googlecode.com/svn/trunk/src/Elmah/SQLServer.sql
感謝你的回應,已修改連結。
刪除請問改成SQL去存放錯誤訊息之後,原本的ELMAH頁面會開不起來嗎?
回覆刪除如果一切按照步驟去做,是可以正常開啟的
刪除要是真的有這個問題的話,網路上早就一堆這樣的問題與討論,我也不會寫文章介紹啦
你給 Elamh 的資料庫連接字串與名稱是否正確,你的 SQL Server 是否允許對外連線
是否有自己去修改過 Elmah 給的 Sql Schema 內容
我沒有天眼通,所以無法依據你的隻字片語去協助你解決問題
我也覺得應該可以正常開啟才對啊啊啊啊啊啊
刪除感謝回覆,我再重新檢視一下我的SQL,謝謝Kevin!
ELMAH 搬到 Github 囉
回覆刪除http://elmah.github.io/