Simple error trapping class for LotusScript

I wrote this class to simplify and standardize our error trapping/handling procedures in LS code.

This Content Component encountered an error

I wrote this class to simplify and standardize our error trapping/handling procedures in LS code. The class has 3 public subs:
(1) SendToErrorsDB,
(2) LogToMail, and
(3) LogToAgentLog.

To make use of the class, put it in your error handling code -- something like:

sub main()
	On Error goto errorHandler
	Dim snafu as RunTimeError

	code, code, code . . .
	exit sub

errorHandler:
	Set snafu = New RunTimeError(Err, Error, Erl, "main subroutine", True, True)
	Msgbox snafu.ErrorMessage & ".", , snafu.MbTitle
	Call snafu.SendToErrorsDB
	Call snafu.LogToMail
	Delete snafu
	exit sub
End sub

Additional Notes:
(1) You can allow the constructor to show the error message OR suppress it and show it yourself (as above).

(2) To use the SendToErrorsDB sub, you'll need to set up a mail-in database with an "Error Record" form containing these fields:

    DateEncountered,
    SourceServer,
    SourceDBTitle,
    SourceDBPath,
    SourceDBRepID,
    DesignElement,
    ErrorNum,
    ErrorDesc,
    ErrorLine, and
    IsUIError.

The name for the mail-in database needs be recorded in the ERRORS_DB_NAME constant in the SendToErrorsDB sub for it to work (if you don't want to use a mail-in database, just don't call this subroutine).

(3) The class allows you to indicate the context (ie, UI or backend) in which the error occurred. See the constructor for details.

Happy error-trapping! dgg Code starts here: the code is too long to fit entirely in the code section below:

Public Class RunTimeError
'//	IMPORTANT NOTE:
'//	In the event of an error encountered within a public method of 
this class, the class falls '// back on the sendLog sub. Private errSession As NotesSession Private sourceDb As NotesDatabase Private errNo As Long Private line As Integer Private isUIError As Integer Private className As String Private serverName As String Private dbName As String Private dbPath As String Private fullMsg As String Private desc As String Private codeElement As String
	
	Sub New(errNum As Variant, errMsg As String, lineNum As Integer, 
designElement As String, isUI As Integer, suppress As Integer) '//////////////////////////////////////////////////////////////////////
'// AUTHOR: '// Dallas Gimpel '// '// DATE OF CREATION: '// 12/18/2001 '// '// DESCRIPTION: '// This is the class constructor for the "RunTimeError" class. '// '// INPUT: '// errNum = variant, the number of the error encountered (Err) '// errMsg = string, the text associated with the error
encountered (Error) '// lineNum = integer, line at which the error was encountered (Erl) '// designElement = string, design element in which the error
was encountered '// isUI = integer (boolean), flag indicating that the error
was encountered in the UI '// '// OUTPUT: '// n/a
code continues below
'//////////////////////////////////////////////////////////////////////
On Error Goto errorHandler Const CLASS_NAME$ = """RunTimeError"" class" Const CODE_ELEMENT$ = """New"" subroutine (class constructor)" Const LSI_THREAD_CALLPROC% = 10 Set Me.errSession = New NotesSession Set Me.sourceDb = Me.errSession.CurrentDatabase Stop Me.className$ = CLASS_NAME Me.serverName$ = sourceDb.Server Me.dbName$ = sourceDb.Title Me.dbPath$ = sourceDb.FilePath Me.errNo& = Clng(errNum) Me.line% = lineNum% Me.isUIError% = isUI% Me.desc$ = errMsg$ Me.codeElement$ = designElement$ '// This is just a precaution (in the event that we are passed
an inaccurate argument). If Me.errSession.IsOnServer Then Me.isUIError% = False '// If we get an empty string for the designElement argument,
use the source of the call. If Me.codeElement$ = "" Then Me.codeElement$ = Getthreadinfo(LSI_THREAD_CALLPROC) End If Me.fullMsg$ = "Error " & Me.errNo & " (" & Me.desc$ & ") at
line " & Me.line% & " of " & Me.codeElement$ If Me.isUIError% Then If Not(suppress%) Then Msgbox Me.fullMsg$ & ".", , Me.MbTitle$ End If End If Print Me.fullMsg$ & " ! ! !" Exit Sub errorHandler: If Me.isUIError% Then Msgbox "Error " & Err & " (" & Error & ") at line " &
Erl & " of " & Me.className$ & " / " & CODE_ELEMENT & " called from " &
Getthreadinfo(LSI_THREAD_CALLPROC) & ".", , "Error encountered . . ." Else Print "Error " & Err & " (" & Error & ") at line " &
Erl & " of " & Me.className$ & " / " & CODE_ELEMENT & " called from " &
Getthreadinfo(LSI_THREAD_CALLPROC) & "." End If Stop '// If we get an error in the class, we want to report the
original error & the class error. Call Me.sendLog("ORIGINAL: " & Me.desc$, Me.line%,
Me.codeElement$) Call Me.sendLog("Error " & Err & " (" & Error$ & ")", Erl,
Me.className$ & " / " & CODE_ELEMENT & " called from " &
Getthreadinfo(LSI_THREAD_CALLPROC)) End End Sub Public Property Get ErrorMessage As String ErrorMessage$ = Me.fullMsg$ End Property Public Property Get MbTitle As String MbTitle$ = "Error encountered . . ." End Property '// **** PUBLIC SUBS & FUNCTIONS **** Public Sub SendToErrorsDB '//////////////////////////////////////////////////////////////////////
'// AUTHOR: '// Dallas Gimpel '// '// DATE OF CREATION: '// 12/18/2001 '// '// DESCRIPTION: '// This public subroutine records error information in a Notes
document. When all data is '// recorded, the resulting document is sent to a mail-in
database (as defined by the '// "ERRORS_DB_NAME" constant) where it can be scrutinized. '// '// INPUT: '// none '// '// OUTPUT: '// none '//////////////////////////////////////////////////////////////////////
On Error Goto errorHandler Const CODE_ELEMENT$ = "SendToErrorsDB subroutine" Const ERRORS_DB_NAME$ = "Lotus Notes Errors db" '// name
specified in mail-in document Const LSI_THREAD_CALLPROC% = 10 Dim errDoc As NotesDocument Dim srcDbRepID As String Set errDoc = New NotesDocument(Me.sourceDb) srcDbRepID$ = Me.sourceDb.ReplicaID srcDbRepID$ = Left(srcDbRepID$, Len(srcDbRepID$) / 2) &
Chr(58) & Right(srcDbRepID$, Len(srcDbRepID$) / 2) Call errDoc.ReplaceItemValue("Form", "Error Record") Call errDoc.ReplaceItemValue("SendTo", ERRORS_DB_NAME) Call errDoc.ReplaceItemValue("DateEncountered", errDoc.Created) Call errDoc.ReplaceItemValue("SourceServer", Me.serverName$) Call errDoc.ReplaceItemValue("SourceDBTitle", Me.dbName$) Call errDoc.ReplaceItemValue("SourceDBPath", Me.dbPath$) Call errDoc.ReplaceItemValue("SourceDBRepID", srcDbRepID$) Call errDoc.ReplaceItemValue("DesignElement", Me.codeElement$) Call errDoc.ReplaceItemValue("ErrorNum", Me.errNo&) Call errDoc.ReplaceItemValue("ErrorDesc", Me.desc$) Call errDoc.ReplaceItemValue("ErrorLine", Me.line%) If Me.isUIError% Then Call errDoc.ReplaceItemValue("IsUIError", "1") Else Call errDoc.ReplaceItemValue("IsUIError", "0") End If Call errDoc.Send(False) Exit Sub errorHandler: If Me.isUIError% Then Msgbox "Error " & Err & " (" & Error & ") at line " &
Erl & " of " & Me.className$ & " / " & CODE_ELEMENT & " called from " &
Getthreadinfo(LSI_THREAD_CALLPROC) & ".", , "Error encountered . . ." Else Print "Error " & Err & " (" & Error & ") at line " &
Erl & " of " & Me.className$ & " / " & CODE_ELEMENT & " called from " &
Getthreadinfo(LSI_THREAD_CALLPROC) & "." End If Stop '// If we get an error in the class, we want to report the
original error & the class error. Call Me.sendLog("ORIGINAL: " & Me.desc$, Me.line%, Me.codeElement$) Call Me.sendLog("Error " & Err & " (" & Error$ & ")", Erl,
Me.className$ & " / " & CODE_ELEMENT & " called from " &
Getthreadinfo(LSI_THREAD_CALLPROC)) End End Sub Public Sub LogToMail '//////////////////////////////////////////////////////////////////////
'// AUTHOR: '// Dallas Gimpel '// '// DATE OF CREATION: '// 12/18/2001 '// '// DESCRIPTION: '// This public subroutine uses the NotesLog class to report an
error to designated personnel '// via email notification. '// '// INPUT: '// none '// '// OUTPUT: '// none '//////////////////////////////////////////////////////////////////////
On Error Goto errorHandler Const CODE_ELEMENT$ = """LogToMail"" subroutine" Const LSI_THREAD_CALLPROC% = 10 Dim nLog As NotesLog Dim sendTo As Variant Set nLog = New NotesLog(Me.dbName$ & ": " & Me.codeElement$) sendTo = getRecipients(Me.errSession) '// NOTE: the
"getRecipients" function is in this script library Call nLog.OpenMailLog(sendTo, Me.dbName$ & ": Error log for
" & Me.codeElement$ & " . . .") Call nLog.LogError(Me.errNo&, Me.desc$ & " encountered at
line " & Me.line% & " of " & Me.codeElement$) Call nLog.Close '// causes Notes log to be sent Exit Sub errorHandler: If Me.isUIError% Then Msgbox "Error " & Err & " (" & Error & ") at line " &
Erl & " of " & Me.className$ & " / " & CODE_ELEMENT & " called from " &
Getthreadinfo(LSI_THREAD_CALLPROC) & ".", , "Error encountered . . ." Else Print "Error " & Err & " (" & Error & ") at line " &
Erl & " of " & Me.className$ & " / " & CODE_ELEMENT & " called from " &
Getthreadinfo(LSI_THREAD_CALLPROC) & "." End If Stop '// If we get an error in the class, we want to report the
original error & the class error. Call Me.sendLog("ORIGINAL: " & Me.desc$, Me.line%, Me.codeElement$) Call Me.sendLog("Error " & Err & " (" & Error$ & ")", Erl,
Me.className$ & " / " & CODE_ELEMENT & " called from " &
Getthreadinfo(LSI_THREAD_CALLPROC)) End End Sub Public Sub LogToAgentLog(agentLog As NotesLog, logPath As String) '//////////////////////////////////////////////////////////////////////
'// AUTHOR: '// Dallas Gimpel '// '// DATE OF CREATION: '// 12/18/2001 '// '// DESCRIPTION: '// This public subroutine uses the NotesLog class to record a
given error to an AgentLog '// Notes database (ie, a database whose design is based on
StdR4AgentLog template). The '// subroutine can be called using "Nothing" for the agentLog
parameter in which case it '// will try to access the agent log by way of the path
parameter. If the sub is called '// with "Nothing" for the first parameter and an empty string
for the second, it exits. '// '// INPUT: '// agentLog = NotesLog instance (or nothing), Noteslog
database to which error is logged '// logPath = string, path to the Agentlog database in which
the error should be recorded '// '// OUTPUT: '// none '//////////////////////////////////////////////////////////////////////
On Error Goto errorHandler Const CODE_ELEMENT$ = """LogToAgentLog"" subroutine" Const LSI_THREAD_CALLPROC% = 10 If agentLog Is Nothing Then If logPath$ = "" Then Exit Sub Else Set agentLog = New NotesLog(Me.serverName$ &
"!!" & Me.dbPath$ & " (" & Me.dbName$ & " - " & Me.codeElement$ & ")") End If End If If Me.IsUIError% Then Call agentLog.OpenNotesLog(Me.serverName$, logPath$) Else Call agentLog.OpenNotesLog("", logPath$) End If agentLog.LogActions = True agentLog.LogErrors = True Call agentLog.LogError(Me.errNo&, Me.desc$ & " at line " &
Me.line% & " of " & Me.codeElement$) Exit Sub errorHandler: If Me.isUIError% Then Msgbox "Error " & Err & " (" & Error & ") at line " &
Erl & " of " & Me.className$ & " / " & CODE_ELEMENT & " called from " &
Getthreadinfo(LSI_THREAD_CALLPROC) & ".", , "Error encountered . . ." Else Print "Error " & Err & " (" & Error & ") at line " &
Erl & " of " & Me.className$ & " / " & CODE_ELEMENT & " called from " &
Getthreadinfo(LSI_THREAD_CALLPROC) & "." End If Stop '// If we get an error in the class, we want to report the
original error & the class error. Call Me.sendLog("ORIGINAL: " & Me.desc$, Me.line%,
Me.codeElement$) Call Me.sendLog("Error " & Err & " (" & Error$ & ")", Erl,
Me.className$ & " / " & CODE_ELEMENT & " called from " &
Getthreadinfo(LSI_THREAD_CALLPROC)) End End Sub Private Sub sendLog(msg As String, lineNum As Integer,
codeElement As String) '//////////////////////////////////////////////////////////////////////
'// AUTHOR: '// Dallas Gimpel '// '// DATE OF CREATION: '// 09/14/2001 - Dallas Gimpel '// '// DESCRIPTION: '// This subroutine sends a Notes log with the text of the
given error, the line number '// at which the error was encountered, and the design (code)
element in which the error '// was encountered. '// '// INPUT: '// msg = String (text of the error message in question) '// lineNum = Integer (line number at which the error occurred) '// codeElement = String (the "code element" in which the error occurred) '// '// OUTPUT: '// none Const LSI_THREAD_CALLPROC% = 10 Dim logSession As NotesSession Dim nLog As NotesLog Dim dbTitle As String Dim sendTo As Variant Set logSession = New NotesSession dbTitle$ = logSession.CurrentDatabase.Title If codeElement$ = "" Then codeElement$ = Getthreadinfo(LSI_THREAD_CALLPROC) End If sendTo = "Notes Developers" '// OR use a function to
determine recipients -> getRecipients(logSession) Call nLog.OpenMailLog(sendTo, dbTitle$ & ": Error log for "
& codeElement$ & " . . .") Call nLog.LogAction(msg$ & " encountered at line " &
lineNum% & " in " & codeElement$) Call nLog.Close End Sub End Class
This was first published in April 2002

Dig deeper on Domino Resources - Part 5

0 comments

Oldest 

Forgot Password?

No problem! Submit your e-mail address below. We'll send you an email containing your password.

Your password has been sent to:

-ADS BY GOOGLE

SearchWinIT

Search400

  • iSeries tutorials

    Search400.com's tutorials provide in-depth information on the iSeries. Our iSeries tutorials address areas you need to know about...

  • V6R1 upgrade planning checklist

    When upgrading to V6R1, make sure your software will be supported, your programs will function and the correct PTFs have been ...

  • Connecting multiple iSeries systems through DDM

    Working with databases over multiple iSeries systems can be simple when remotely connecting logical partitions with distributed ...

SearchEnterpriseLinux

SearchVirtualDataCentre.co.UK

Close