.<1> - }
Overview
Sample Implementation
1. Create the Journal
table in the database. If appropriate for your implementation, change the data type for the UserId
field to varchar
.
2. Create the stored procedure dbo.InsertJournalEntry
. If appropriate for your implementation, change the data type for the UserId
field to varchar
.
3. Create the Journal
class
4. Create the Error.aspx
page
5. Create/edit the Global.asax
page
6. Add exception handling to all procedures, and include the following line before the throw ex
line.
VB.NET
{copytext|ErrorHandlerVb}
Journal.Write(ex) : HttpContext.Current.Response.End()
C#
{copytext|ErrorHandlerCs}
Journal.Write(ex); HttpContext.Current.Response.End();
Source Code
Journal Table
{copytext|JournalTable}
CREATE TABLE dbo.Journal(
JournalId int IDENTITY(1,1) NOT NULL,
LoggedAt datetime NOT NULL CONSTRAINT DF_Journal_LoggedAt DEFAULT (getutcdate()),
Severity tinyint NOT NULL,
Message varchar(1000) NOT NULL,
Detail varchar(1000) NOT NULL,
ModName varchar(300) NOT NULL,
ProcName varchar(300) NOT NULL,
LineNum int NOT NULL,
RemoteIP varchar(15) NOT NULL,
UserId uniqueidentifier NULL,
FullUrl varchar(1000) NOT NULL,
StackTrace varchar(max) NOT NULL,
CONSTRAINT PK_Journal PRIMARY KEY CLUSTERED
(
JournalId ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
InsertJournalEntry Stored Procedure
{copytext|InsertJournalEntrySp}
create procedure dbo.InsertJournalEntry
(
@Severity tinyint
,@Message varchar(1000)
,@Detail varchar(1000)
,@StackTrace varchar(max)
,@ModName varchar(300)
,@ProcName varchar(300)
,@LineNum int
,@RemoteIP varchar(15)
,@UserId uniqueidentifier
,@FullUrl varchar(1000)
) as
INSERT INTO dbo.Journal (
LoggedAt
,Severity
,Message
,Detail
,StackTrace
,ModName
,ProcName
,LineNum
,RemoteIP
,UserId
,FullUrl
)
select
LoggedAt = getutcdate()
,Severity = @Severity
,Message = @Message
,Detail = @Detail
,StackTrace = @StackTrace
,ModName = @ModName
,ProcName = @ProcName
,LineNum = @LineNum
,RemoteIP = @RemoteIP
,UserId = @UserId
,FullUrl = @FullUrl
Journal Class
VB.NET
{copytext|JournalVb}
Imports Microsoft.VisualBasic
Imports System.Diagnostics
Imports System.Reflection
Imports System.Data
Imports System.Data.SqlClient
Public Class Journal
Inherits SqlDatabaseWeb
Private _dbName As String = "RequestTracker"
Public Shared Sub Write(ByVal exception As Exception, Optional ByVal detail As String = "", _
Optional ByVal userId As String = "")
' Ignore ThreadAbortExceptions because they're caused by Response.Redirect() and Response.End()
If Not (TypeOf (exception) Is System.Threading.ThreadAbortException) Then
Dim msg As String = ""
Try
msg = "Couldn't initialize variables"
Dim severity As Byte = 1 ' 1 = error
Dim message As String = exception.Message
Dim stackTrace As String = exception.StackTrace
Dim lineNum As Integer = GetLineNumber(stackTrace)
Dim modName As String = ""
Dim procName As String = ""
Dim request As HttpRequest = HttpContext.Current.Request
Dim remoteIp As String = request.UserHostAddress
Dim fullUrl As String = request.RawUrl
Dim sf As StackFrame = New StackFrame(1, True)
If sf IsNot Nothing Then
msg = "Couldn't get method base"
Dim mb As MethodBase = sf.GetMethod()
If mb IsNot Nothing And mb.DeclaringType IsNot Nothing Then
msg = "Couldn't get modname"
modName = mb.DeclaringType.FullName
msg = "Couldn't get procname"
procName = mb.Name
If lineNum = 0 Then
msg = "Couldn't get line number"
lineNum = sf.GetFileLineNumber()
End If
End If
End If
msg = "Couldn't instantiate Journal"
Dim log As Journal = New Journal()
msg = "Couldn't insert journal entry"
log.InsertJournalEntry(severity, message, detail, stackTrace, modName, procName, _
lineNum, remoteIp, userId, fullUrl)
msg = "Couldn't redirect to Error.aspx"
HttpContext.Current.Response.Redirect("Error.aspx", False)
msg = "Couldn't end response"
HttpContext.Current.Response.End()
Catch ex As Exception
Throw ex
End Try
End If
End Sub
Public Sub InsertJournalEntry(ByVal severity As Byte, ByVal message As String, ByVal detail _
As String, ByVal stackTrace As String, ByVal modName As String, ByVal procName As String, _
ByVal lineNum As Integer, ByVal remoteIp As String, ByVal userId As String, ByVal fullUrl As _
String)
Dim conn As SqlConnection = Nothing
Dim cmd As SqlCommand = Nothing
Try
conn = MyBase.OpenConnection(_dbName)
cmd = MyBase.PrepCommand(conn, "dbo.InsertJournalEntry")
cmd.Parameters.AddWithValue("Severity", severity)
cmd.Parameters.AddWithValue("Message", message)
cmd.Parameters.AddWithValue("Detail", detail)
cmd.Parameters.AddWithValue("StackTrace", stackTrace)
cmd.Parameters.AddWithValue("ModName", modName)
cmd.Parameters.AddWithValue("ProcName", procName)
cmd.Parameters.AddWithValue("LineNum", lineNum)
cmd.Parameters.AddWithValue("RemoteIp", remoteIp)
If userId.Length = 0 Then
cmd.Parameters.AddWithValue("UserId", DBNull.Value)
Else
cmd.Parameters.AddWithValue("UserId", userId)
End If
cmd.Parameters.AddWithValue("FullUrl", fullUrl)
cmd.ExecuteNonQuery()
Catch ex As Exception
Throw ex
Finally
MyBase.CleanUp(conn, cmd)
End Try
End Sub
Private Shared Function GetLineNumber(ByVal stackTrace As String) As Integer
Dim result As Integer = 0
Dim pos As Integer = stackTrace.LastIndexOf(" ")
If pos > -1 Then
Dim s As String = stackTrace.Substring(pos)
If Not Integer.TryParse(s, result) Then
result = 0
End If
End If
Return result
End Function
End Class
C#
{copytext|JournalCs}
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using LibSystem.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Reflection;
public class Journal : SqlDatabaseWeb
{
private string _dbName = "SeinfeldDb";
public static void Write(Exception exception, string detail, string userId)
{
if (!((exception) is System.Threading.ThreadAbortException))
{
try
{
byte severity = 1; // 1 = error
string message = exception.Message;
string stackTrace = exception.StackTrace;
int lineNum = GetLineNumber(stackTrace);
string modName = "";
string procName = "";
HttpRequest request = HttpContext.Current.Request;
string remoteIp = request.UserHostAddress;
string fullUrl = request.RawUrl;
StackFrame sf = new StackFrame(1, true);
if (sf != null)
{
MethodBase mb = sf.GetMethod();
if (mb != null && mb.DeclaringType != null)
{
modName = mb.DeclaringType.FullName;
procName = mb.Name;
if (lineNum == 0)
lineNum = sf.GetFileLineNumber();
}
}
Journal log = new Journal();
log.InsertJournalEntry(severity, message, detail, stackTrace, modName, procName, lineNum,
remoteIp, userId, fullUrl);
HttpContext.Current.Response.Redirect("~/Error.aspx");
HttpContext.Current.Response.End();
}
catch (Exception ex)
{
throw ex;
}
}
}
public void InsertJournalEntry(byte severity, string message, string detail, string stackTrace,
string modName, string procName, int lineNum, string remoteIp, string userId, string fullUrl)
{
SqlConnection conn = null;
SqlCommand cmd = null;
try
{
conn = base.OpenConnection(_dbName);
cmd = base.PrepCommand(conn, "dbo.InsertJournalEntry");
cmd.Parameters.AddWithValue("Severity", severity);
cmd.Parameters.AddWithValue("Message", message);
cmd.Parameters.AddWithValue("Detail", detail);
cmd.Parameters.AddWithValue("StackTrace", stackTrace);
cmd.Parameters.AddWithValue("ModName", modName);
cmd.Parameters.AddWithValue("ProcName", procName);
cmd.Parameters.AddWithValue("LineNum", lineNum);
cmd.Parameters.AddWithValue("RemoteIp", remoteIp);
if (userId.Length == 0)
cmd.Parameters.AddWithValue("UserId", DBNull.Value);
else
cmd.Parameters.AddWithValue("UserId", userId);
cmd.Parameters.AddWithValue("FullUrl", fullUrl);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
throw ex;
}
finally
{
base.CleanUp(ref conn, ref cmd);
}
}
private static int GetLineNumber(string stackTrace)
{
int result = 0;
int pos = stackTrace.LastIndexOf(' ');
if (pos > -1)
{
string s = stackTrace.Substring(pos);
if (!int.TryParse(s, out result))
result = 0;
}
return result;
}
}
Error.aspx
{copytext|ErrorAspx}
<%@ Page Title="Error" %>
<html>
<body>
<asp:Label runat="server" Font-Size="Medium" ForeColor="red" Font-Bold="true" Text="Error" />
<br />
<asp:Label runat="server">An error has occured. This error has been logged, and the webmaster
has been notified. If you were saving data, your changes were most likely lost, and you will
need to try again.</asp:Label>
</body>
</html>
Application_Error Event Handler¶
Include the following code in your Global.asax
file.
VB.NET
{copytext|ApplicationErrorVb}
Sub Application_Error(ByVal sender as Object, ByVal e As EventArgs)
' Code that runs when an unhandled error occurs
Journal.Write(Server.GetLastError(), "", "")
End Sub
C#
{copytext|ApplicationErrorCs}
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
Journal.Write(Server.GetLastError(), "", "");
}