TRACKING ERRORS BY USING A CUSTOM ERROR LOG

One thing that users have a hard time doing is remembering what they were doing when an error occurred. By creating an error log, you can track errors as they happen and program to deal with them the next time around.

Before creating an error log, you need to set up a few constants and variables. Both the constants and the error log routine, ap_ErrorLog, are found in the modErrorHandling module.

The Declarations Section for Error Log Routines

Listing 7.12 shows the declarations section of the modErrorHandling module.

Listing 7.12. VideoApp.mdb: Error Log Routine Declarations
Option Compare Database
Option Explicit

'-- Constants for how to handle the error.
Public Const apTryAgain = 1
Public Const apExitApplication = 2
Public Const apExitRoutine = 3
Public Const apResumeNext = 4
Public Const apMultiUser = 5

'-- Number of times to retry locks
Public Const apMaxMURetries = 2

'-- Variables to store error information
Public apCurrErrNo As Long
Public apCurrErrMsg As String

'-- Each module needs to have this for the Error Log
Const apModuleError = "ModErrorHandling"

Const apDivisionByZero = 11
''''ModErrorHandling

These major items are declared:

  • The constants used to specify how to handle the error. These are used in the ap_ErrorHandler routine, which is discussed in the next section.

  • The number of times to retry locks, used in the ap_ErrorTryMUAgain() function.

  • The variables to store error information (seen in each error handler). The following code, discussed in the next section, shows the variables in use:

    Case apTryAgain
       Resume
    Case apExitRoutine
       Exit Sub
    Case apResumeNext
       Resume Next
    
  • The module constant that's passed to the error log. This line of code declares the constant:

    Const apModuleError = "modErrorHandling"
    

An Example Error Handler Calling the Error Log

Listing 7.13 showsthe code for the cmdTestErrorCollection command button's OnEvent event, located on the TestErrors form.

Listing 7.13. VideoApp.mdb: Calling the Error Log Routine
Private Sub cmdTestErrorCollection_Click()

   '-- Variable for sending the current module to the error log
   Dim apRoutineError As String
   apRoutineError = "cmdTestErrorCollection_Click"

   Dim dbDummy As Database

   On Error GoTo Error_cmdTestErrorCollection_Click

   '-- Purposefully set off a DAO file not found error
   Set dbDummy = DBEngine(0).OpenDatabase("NoDB")

   Exit Sub

Error_cmdTestErrorCollection_Click:

   '-- Store the current err object info to variables
   apCurrErrNo = Err.Number
   apCurrErrMsg = Err.Description

   ap_ErrorLog apModuleError, apRoutineError, apCurrErrNo, apCurrErrMsg
   Select Case ap_ErrorHandler(apCurrErrNo, apCurrErrMsg)
       Case apTryAgain
           Resume
       Case apExitRoutine
           Exit Sub
       Case apResumeNext
           Resume Next
   End Select

End Sub

The first items in this routine are the lines

'-- Variable for sending the current module to the error log
Dim apRoutineError As String
apRoutineError = "cmdTestErrorCollection_Click"

These lines store the name of the current routine in the apRoutineError variable, which is passed to the ap_ErrorLog error log routine. Before this routine is called, the Err object information is stored in variables for future use. This occurs in the next few lines of code, with the ap_ErrorLog routine called next:

'-- Store the current Err object info to variables
apCurrErrNo = Err.Number
apCurrErrMsg = Err.Description

ap_ErrorLog apModuleError, apRoutineError, apCurrErrNo, _
   apCurrErrMsg
						

The Information Tracked for Each Error

The ap_ErrorLog routine allows you to track the following information for errors:

  • The module in which the error occurred. It's useful if you can jump right to the offending module, or perhaps sort the error log by module and then by routine to organize the debugging workload.

  • The routine where the error occurred. Again, this helps find exactly where the problem was.

  • The error number, as retrieved from the Err object.

Tip

Storing the error information in variables as soon as you get into an error handler is a good idea. If another error occurs after the first error, but before the first error can be handled, you might handle the wrong error.


  • The error message as retrieved from the Err object.

  • The active form at the time the error occurred.

  • The active control at the time the error occurred.

  • The current user's name, according to Windows 95 or Windows NT.

  • The current user's computer name, according to Windows 95/98 or Windows NT.

Note

Two routines are used—one for the computer name and one for the username. These routines, ap_GetUserName() and ap_GetComputerName(), use Windows API calls and are described in detail in Chapter 15.


  • The current date and time when the error occurred, using the Now system variable.

  • All the Jet errors that occurred, if any.

Examining the Actual Error Log Code

Listing 7.14 shows the code for ap_ErrorLog, the routine that records the errors.

Listing 7.14. VideoApp.mdb: Logging an Error
Sub ap_ErrorLog(strModule, strRoutine, lngErrorNo As Long, strErrorMsg _
   As String)
   Dim strFormName As String
   Dim strControlName As String
   Dim strTempErrs As String
   Dim dbError As Database
   Dim tblErrors As Recordset
   Dim intTrans As Integer
   Dim errCurrent As Error

   '-- Store the name of the active form and control
   strFormName = ""
   strControlName = ""

   On Error Resume Next

   strFormName = Screen.ActiveForm.Name
   strControlName = Screen.ActiveControl.Name

   '-- Attempt to open the errorlog table on the backend
   Set dbError = _
       DBEngine(0).OpenDatabase(ap_GetDatabaseProp(CurrentDb(), _
      "LastBackEndPath") & ap_GetDatabaseProp(CurrentDb(), _
      "BackEndName"))
   '-- If there is a problem, open the local errorlog table
   If Err Then Set dbError = CurrentDb()

   On Error GoTo Error_ap_ErrorLog

   Set tblErrors = dbError.OpenRecordset("tblErrorLog")

   '-- Log the information
   tblErrors.LockEdits = False

   BeginTrans

   intTrans = True

   tblErrors.AddNew

      tblErrors!ErrModule = strModule
      tblErrors!ErrRoutine = strRoutine
      tblErrors!ErrNumber = lngErrorNo
      tblErrors!ErrMessage = strErrorMsg
      tblErrors!ErrForm = strFormName
      tblErrors!ErrControl = strControlName
      tblErrors!UserName = ap_GetUserName()
      tblErrors!ComputerName = ap_GetComputerName()
      tblErrors!Occured = Now

      '-- Test for DAO Errors
      Errors.Refresh

      If Errors.Count > 0 Then

           '-- Make sure the current error in
           '-- the Errors Collection matches the current error
           If Errors(0).Number = lngErrorNo Then

                '-- Concatenate the errors into a string
                strTempErrs = ""

                '-- Loop through the Errors collection
                For Each errCurrent In Errors
                   strTempErrs = strTempErrs & Str(errCurrent.Number) & _
                      " - " & errCurrent.Description & vbCrLf
                Next errCurrent

                '-- Now put it in the table
                tblErrors!DAOErrors = strTempErrs
            End If
      End If
   tblErrors.UPDATE

   CommitTrans

   intTrans = False

DBEngine.Idle

   tblErrors.Close

Exit_ap_ErrorLog:

   Exit Sub

Error_ap_ErrorLog:

   '-- centralized error handler
   apCurrErrNo = Err.Number
   apCurrErrMsg = Err.Description

   Select Case ap_ErrorHandler(apCurrErrNo, apCurrErrMsg)

      Case apTryAgain
         Resume

      Case apExitApplication
         Application.Quit

      Case apExitRoutine
         If intTrans Then
            RollBack
         EndIf
         Resume Exit_ap_ErrorLog

      Case apResumeNext
         Resume Next

   End Select

End Sub

Caution

When a BeginTrans is used with an error handler, you need to make sure that you roll back the transaction. Otherwise, the transaction will be in place, with all files left open. In this code, intTrans is used as a flag to tell the error handler whether a transaction has been started. For more information on the RollBack statement, see “Using Your Error Handler to Roll Back Transactions” later in this chapter.


Parts of this code have already been examined. Notice the use of Screen.ActiveForm and Screen.ActiveControl to get the current form and control information for the error log.

Another interesting feature of the error-logging routine is that it tries to log the error to the back end; if that's not possible, it logs the error to the front end (the local application). For more information on front ends and back ends, see Chapter 22, “Handling Multiuser Situations.”

Logging to the Back End First, or Front End if Necessary

This code allows for the possibility that the back end is the cause of the error:

'-- Attempt to open the errorlog table on the backend
Set dbError = _
    DBEngine(0).OpenDatabase(ap_GetDatabaseProp(CurrentDb(), _
   "LastBackEndPath") & ap_GetDatabaseProp(CurrentDb(), _
   "BackEndName"))

'-- If there is a problem, open the local errorlog table
If Err Then Set dbError = CurrentDb()

Following an On Error Resume Next statement, the first line tries to open the back end by using the path and filename stored in the custom database properties LastBackEndPath and BackEndName. If an error occurs, the database variable dbError is set to the current database.

The back end and front end have the same table, named tblErrorLog. Figure 7.8 shows the Design view of tblErrorLog.

Figure 7.8. The structure of the tblErrorLog table is identical in the front-end and back-end databases.


Updating the Back End with Any Errors That Occur

It would be a pain to keep looking at all individual workstations to see whether any errors have occurred on them. To remedy this situation, you can place a routine named ap_ErrorCheckLocal in the system startup routine. This routine does the following:

  • Checks to see whether any errors are in the local tblErrorLog table

  • If there are any errors, copies the errors out to the back end

  • Deletes the errors that were in the front end

Listing 7.15 shows the code for ap_ErrorCheckLocal.

Listing 7.15. VideoApp.mdb: Checking the Local Error Log
Sub ap_ErrorCheckLocal()
    Dim dbLocal As Database
    Dim dynLocalErrs As Recordset
    Dim intAreErrors As Integer

    '-- Variable for recording the name of the routine
    Dim apRoutineError As String
    apRoutineError = "ap_ErrorCheckLocal"

    On Error GoTo Error_ap_ErrorCheckLocal

    Set dbLocal = CurrentDb()
    '-- Open the Local version of the tblErrorLog and
    '-- test for records
    Set dynLocalErrs = dbLocal.OpenRecordset("tblErrorLog")
    intAreErrors = dynLocalErrs.RecordCount
    dynLocalErrs.Close

    '-- If error entries exist, copy them to the backend and delete
    '-- local version
    If intAreErrors Then

        DoCmd.Echo True, "Copying Local Errors into backend..."
        dbLocal.Execute "INSERT INTO tblErrorLog IN '" & _
           ap_GetDatabaseProp(dbLocal, "LastBackEndPath") & _
           ap_GetDatabaseProp(dbLocal, "BackEndName") & "' SELECT _
           DISTINCTROW tblErrorLog.* FROM tblErrorLog;"
        dbLocal.Execute "DELETE * FROM tblErrorLog"
        DoCmd.Echo True

    End If
   Exit Sub

Error_ap_ErrorCheckLocal:
   '-- Store Error information into variables for future use.
   apCurrErrNo = Err.Number
   apCurrErrMsg = Err.Description

   ap_ErrorLog apModuleError, apRoutineError, apCurrErrNo, apCurrErrMsg
   Select Case ap_ErrorHandler(apCurrErrNo, apCurrErrMsg)
       Case apTryAgain
           Resume
       Case apExitRoutine
           Exit Sub
       Case apResumeNext
           Resume Next
   End Select

End Sub

This routine rounds out the error-logging routines. Again, you can create reports to examine errors and fix them. Figure 7.9 shows such a report.

Figure 7.9. You can create various reports to track errors so you can fix them.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.216.249