5. Centralize the handling of errors, but make use of all contextual information.
Putting all of the above practices together gives you a richer context in which to report errors. The actual logic of reporting the error is something that you can implement in a centralized way. In this code example, a critical exception is caught. It is then passed to the central method called HandleError() to be read and logged. HandleError() subsequently calls LogEvent(), which is discussed in #6, below.
Dim sPath As String = "\\MYSERVER\myshare\myfile.txt"
Catch ex As System.IO.FileNotFoundException
HandleError(ex, EventImportance.Critical, EventID.FILE_ACCESS_ERROR, _
"[Delete failed: can't access path.]")
Public Sub HandleError(ByRef e As Exception, ByVal Importance As EventImportance, _
ByVal ID As EventID, ByVal ExtraInfo As String)
Dim sMessage As String
While Not e.InnerException Is Nothing
e = e.InnerException
sMessage += Chr(13) + e.Message + " [" + e.GetType().ToString() + "]"
If ExtraInfo <> "" Then
sMessage += Chr(13) + ExtraInfo
LogEvent(sMessage, Importance, ID)
6. Report application errors to the Windows Event Logs
The Windows Event Logs provide an existing infrastructure that can be leveraged in the task of Enterprise error handling. It provides the same reliable error logging as used by the OS, and additionally offers sorting, filtering, and growth control of logs.
Private Sub LogEvent(ByVal Msg As String, ByVal Type As EventImportance, ByVal ID As Integer)
Dim sEventLogName = "Application"
Dim elog As New System.Diagnostics.EventLog(sEventLogName)
elog.Source = GetAssemblyName()
If AlreadyLogged(elog, ID, Msg) Then Exit Sub
Dim EventType As System.Diagnostics.EventLogEntryType
Select Case Type
EventType = System.Diagnostics.EventLogEntryType.Error
EventType = System.Diagnostics.EventLogEntryType.Information
EventType = System.Diagnostics.EventLogEntryType.Warning
elog.WriteEntry(Msg, EventType, ID)
Catch ex As System.ComponentModel.Win32Exception
WriteFile("Windows Event Log [" + sEventLogName + "] is full! " + GetAssemblyName() _
+ " application failed to write error " + ID.ToString + ": " + Msg)
Catch ex As Exception
WriteFile("Unknown error writing to Windows Event Log [" + sEventLogName + "]!" + _
ex.Message + GetAssemblyName() + _
" application failed to write error " + ID.ToString + ": " + Msg)
Private Function GetAssemblyName() As String
Dim assemb As Reflection.Assembly = Reflection.Assembly.GetExecutingAssembly()
Dim attr As System.Attribute
For Each attr In assemb.GetCustomAttributes(False)
If TypeOf attr Is System.Reflection.AssemblyTitleAttribute Then
GetAssemblyName = CType(attr, System.Reflection.AssemblyTitleAttribute).Title
Private Function AlreadyLogged(ByRef Log As System.Diagnostics.EventLog, _
ByVal ID As Integer, ByVal Message As String) As Boolean
Dim entr As System.Diagnostics.EventLogEntry
AlreadyLogged = False
For Each entr In Log.Entries
If entr.EventID = ID And entr.Message = Message Then
AlreadyLogged = True
7. Ensure all apps are able to report to the Windows Event Logs
With Windows 2003, security on the Event Logs has changed. You can now define custom Security Descriptors for each log. For example, the following registry key value defines access to the Application Event Log:
You need to configure carefully the various event logs used by your program so that it can log properly to the Event Log in all instances, and under the security context of any potential user. You also need to ensure all users have access to read the above registry key
or you won’t get far.
At the end of this value are tokens such as:
- (A;;0x1;;;DU) - allow domain users to read this event log
- (D;;0x7;;;BG) - deny built-in guest users (e.g. IUSER, ASPNET user) read, write, and clear
- (A;;0x3;;;IU) - allow interactive users to read and write to it
The middle unit of each token is a bitwise AND, in hex format, of 1:read, 2:write, 4:clear.
Other possible values for the last unit of each token include:
- BA (Built-in admin)
- SY (System)
- AN (Anonymous)
- SO (Server operators)
- SU (Service users)
- any SID representing a specific user or group on the machine or domain.
Suggestion 8, References and Links
8. Use enterprise tools to identify and respond to program errors
There are several tools available for monitoring your Event Log remotely, so keeping tabs on multiple servers is not a problem. One such program with which I've had success is Quest Software's Big Brother. A small windows service runs on each server and monitors a multitude of factors including Event Log messages. Reporting of errors can trigger an email or simply update a dashboard display on a single Big Brother server.
Of course you can monitor Event Logs manually across the network using MMC, or programmatically with WMI as well.
.NET Framework Developer's Guide: Best Practices for Handling Exceptions
Microsoft Knowledge Base Article - 315965
HOW TO: Use Structured Exception Handling in Visual Basic .NET
.NET Framework Developer's Guide: Handling and Throwing Exceptions
Choosing When to Use Structured and Unstructured Exception Handling
Development Impacts of Security Changes in Windows Server 2003
http://msdn.microsoft.com/library/en-us/dncode/html/secure06122003.asp (see Tighter ACLs on Event Logs)
Big Brother - http://www.bb4.org/
Monitoring in .NET Distributed Application Design