Page 1 of 2
How to include specific items like a record or line number, in your error handler
Posted: Thu Oct 07, 2021 10:22 pm
by HGAutomator
Hi,
For an error handler for one specific function, I'd like to provide some environmental information at the time of the error.
For example, I'm using the HB_FUse() functions to loop through a text file. If there's an error processing one of the lines, I'd like to send hb_FRecNo() into the error log.
Is there a way to do that?
Re: How to include specific items like a record or line number, in your error handler
Posted: Fri Oct 08, 2021 1:45 am
by AUGE_OHR
hi,
you can use a own Error-Handler and "RECOVER USING" to log Error ( or react on it )
Code: Select all
nHandle := FCreate(cOutDir + "ErrLog.TXT")
FOR i := 1 TO iMax
bError := ERRORBLOCK( { | object | BREAK( object ) } )
BEGIN SEQUENCE
// Action -> Error
RECOVER USING oError
cError := "ERROR: " + oError:description + ;
IIF( EMPTY( oError:operation ), "", ;
HB_OSNEWLINE() + oError:operation ) + ;
HB_OSNEWLINE()
cError += oError:subsystem + "/" + ALLTRIM( STR( oError:subcode ) ) + ;
" (generic code " + ALLTRIM( STR( oError:genCode ) ) + ;
", os code " + ALLTRIM( STR( oError:osCode ) ) + ")" + ;
HB_OSNEWLINE()
ERRORBLOCK( bSaveError )
FWrite( nHandle, cError + CRLF )
END SEQUENCE
ERRORBLOCK( bSaveError )
NEXT
FClose( nHandle )
Re: How to include specific items like a record or line number, in your error handler
Posted: Fri Oct 08, 2021 2:27 am
by HGAutomator
So it's that easy?
Thanks Auge, I thought this was going to involve some cargo property, now I'm really glad I asked on the forum first.
Much appreciated,
Re: How to include specific items like a record or line number, in your error handler
Posted: Fri Oct 08, 2021 2:52 am
by HGAutomator
I was just looking at it more closely, and there doesn't seem to be anything unique about the snippet.
Sorry, I don't see how we would send the error block anything outside of the error object and its properties.
Whether we send it to a log or just display it on the screen with a simple Try Catch, I'm just looking for a way to include external information.
For example, the line number of the text file that was in use. Or the nth field that we're extracting from the text file before the error occurred.
In other words, not just the properties in the Error object, but other variables that were in place at the time of the error, which could make the reason for the error more explicit to the end user.
Re: How to include specific items like a record or line number, in your error handler
Posted: Fri Oct 08, 2021 9:04 am
by serge_girard
What I do is following:
Code: Select all
// xDEFAULT is DRIVE+PATH+...
ZX_ERR_MEMORY = xDEFAULT + '\ERROR.MEM'
SAVE ALL TO &ZX_ERR_MEMORY
memhandle := FOPEN( ZX_ERR_MEMORY, pOPEN_READWRITE )
memlength := FSEEK( memhandle, 0, pSEEK_EOF )
FSEEK( memhandle, 0 )
count := 1
bytes := 0
vars := 0
atemp :={}
? '<table border="1">'
? '<tr><th bgcolor="#00ff00">#</th><th bgcolor="#00ff00">Bytes</th><th bgcolor="#00ff00">Var Name</th><th bgcolor="#00ff00">Type</th><th bgcolor="#00ff00">Value</th></tr>'
tel = 0
DO WHILE FSEEK( memhandle, 0, pSEEK_CURRENT ) + 1 < memlength
memwidth := SPACE(18)
FREAD( memhandle, @memwidth, 18)
vname := LEFT(memwidth, AT( CHR(0), memwidth) -1 )
vtype := SUBSTR(memwidth, 12, 1)
vrec := BIN2W(RIGHT(memwidth,2))
IF ( vtype $ CHR(195) + CHR(204), memcount := 14 + vrec, memcount := 22 )
FSEEK( memhandle, memcount, pSEEK_CURRENT )
IF LEFT( vname, 1) # "_"
tel++
ttemp1 := vname //LEFT( vname + SPACE(10), 10)
ttemp2 := TYPE(vname)
ttemp3 := IF(TYPE(vname) = pCHARACTER, "[" + &vname. + "]", strvalue( &vname.) )
DO CASE
CASE TYPE(vname) = pCHARACTER
bytes += ( atemp := LEN( &vname. ) )
CASE TYPE(vname) = pNUMERIC
bytes += ( atemp := 9 )
CASE TYPE(vname) = pLOGICAL
bytes += ( atemp := 2 )
CASE TYPE(vname) = pDATE
bytes += ( atemp := 9 )
OTHERWISE
bytes += ( atemp := 0 )
ENDCASE
/* SUPPRESS DB AND FTP INFORMATION : don't want to mention secret password etc.... '*/
IF AT('PW', UPPER(ttemp1)) > 0 .OR. ;
AT('USER', UPPER(ttemp1)) > 0 .OR. ;
AT('SITE', UPPER(ttemp1)) > 0 .OR. ;
AT('HOST', UPPER(ttemp1)) > 0 .OR. ;
AT('PASW', UPPER(ttemp1)) > 0 .OR. ;
AT('DB', UPPER(ttemp1)) > 0
ELSE
? '<tr>'
? '<td style="text-align:right;">' + TRANSFORM( tel, "999") + '</td><td style="text-align:right;">' + TRANSFORM( atemp, "9999999") + '</td><td>' + ttemp1 + '</td><td>' + ttemp2 + '</td><td>' + substr(ttemp3,1,100) + '</td>'
? '</tr>'
ENDIF
ENDIF
ENDDO
? '<tr><td bgcolor="#00ff00" colspan=2 style="text-align:right;">' + TRANSFORM( bytes, "9,999,999") + '</td><td bgcolor="#00ff00" colspan=3>Totaal</td></tr>'
? "</table>"
FCLOSE( memhandle )
This will surely help you a bit....
Serge
Re: How to include specific items like a record or line number, in your error handler
Posted: Fri Oct 08, 2021 10:35 am
by AUGE_OHR
hi,
HGAutomator wrote: ↑Fri Oct 08, 2021 2:52 am
For example, the line number of the text file that was in use. Or the nth field that we're extracting from the text file before the error occurred.
In other words, not just the properties in the Error object, but other variables that were in place at the time of the error, which could make the reason for the error more explicit to the end user.
Ok, got it
i wanted to show a general Way to "react" on Error.
i do read TEXT File with MEMOREAD and use MLCOUNT() / MEMOLINE()
Code: Select all
FUNCTION ReadTXTfile( cFilename )
LOCAL cText := MemoRead( cFilename )
LOCAL nMaxLines := MlCount( cText, 80 )
LOCAL aLines[ nMaxLines ], n
FOR n:=1 TO nMaxLines
bError := ERRORBLOCK( { | object | BREAK( object ) } )
BEGIN SEQUENCE
cLine := Trim( MemoLine( cText, 80, n ) )
// we are in "this" Errorblock when Code is execute
IF .NOT. CheckIt(cLine])
BREAK
ENDIF
aLines[ n ] := cLine
RECOVER USING oError
lError := .T.
END SEQUENCE
ERRORBLOCK( bSaveError )
IF lError = .T.
OutPut2Screec("Error Line ",STR(n),a,b,c,d ... )
ENDIF
lError := .F.
NEXT
RETURN aLines
so it is just a Concept to handle Error Problem
Re: How to include specific items like a record or line number, in your error handler
Posted: Fri Oct 08, 2021 11:10 am
by mol
I'm also sending e-mail message to me from application when error occurs.
In this way I can quickly react and analyze error
Re: How to include specific items like a record or line number, in your error handler
Posted: Fri Oct 08, 2021 11:19 am
by serge_girard
Marek, Me too !
Happens happily very seldom!
Serge
Re: How to include specific items like a record or line number, in your error handler
Posted: Fri Oct 08, 2021 1:44 pm
by HGAutomator
Hi mol,
Yep, I do the same thing for our VBScripts. Should start doing it for the Harbour stuff as well.
Code: Select all
Sub udfs_SendErrorMessage( Subject_s, ErrorNumber, ErrorDescription, ErrorSource )
Dim Email_From_s
Dim Email_To_s
Dim Email_o
Dim Error_s
Error_s = Subject_s & ", Error: " & ErrorDescription & ", Error Number: " & ErrorNumber
On Error Resume Next
Set Email_o = CreateObject("CDO.Message")
Email_o.From = NOREPLY_ERRORSTATUS
Email_o.To = SUPPORT_EMAIL
Email_o.CC = PROD_SUPPORT_TEXT
Email_o.ReplyTo = NOREPLY_ERRORSTATUS
Email_o.Subject = Subject_s
Email_o.Textbody = Error_s
Email_o.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
Email_o.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserver") = _
SMTP_SERVER
Email_o.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = SMTP_SERVER_PORT
Email_o.Configuration.Fields.Update
Email_o.Send
If Err.number <> 0 Then
ErrorNumber = Err.number
ErrorDescription = Err.Description
ErrorSource = Err.Source
Err.Clear
Call udfs_LogError( Subject_s, ErrorNumber, ErrorDescription, ErrorSource )
End If
Set Email_o = Nothing
End Sub
mol wrote: ↑Fri Oct 08, 2021 11:10 am
I'm also sending e-mail message to me from application when error occurs.
In this way I can quickly react and analyze error
Re: How to include specific items like a record or line number, in your error handler
Posted: Fri Oct 08, 2021 1:47 pm
by HGAutomator
Thanks Serge,
There's no problem generating the log file. I just want to include items that are normally not part of the error object. Auge answered this, and it looks doable.
serge_girard wrote: ↑Fri Oct 08, 2021 9:04 am
What I do is following:
Code: Select all
// xDEFAULT is DRIVE+PATH+...
ZX_ERR_MEMORY = xDEFAULT + '\ERROR.MEM'
SAVE ALL TO &ZX_ERR_MEMORY
memhandle := FOPEN( ZX_ERR_MEMORY, pOPEN_READWRITE )
memlength := FSEEK( memhandle, 0, pSEEK_EOF )
FSEEK( memhandle, 0 )
count := 1
bytes := 0
vars := 0
atemp :={}
? '<table border="1">'
? '<tr><th bgcolor="#00ff00">#</th><th bgcolor="#00ff00">Bytes</th><th bgcolor="#00ff00">Var Name</th><th bgcolor="#00ff00">Type</th><th bgcolor="#00ff00">Value</th></tr>'
tel = 0
DO WHILE FSEEK( memhandle, 0, pSEEK_CURRENT ) + 1 < memlength
memwidth := SPACE(18)
FREAD( memhandle, @memwidth, 18)
vname := LEFT(memwidth, AT( CHR(0), memwidth) -1 )
vtype := SUBSTR(memwidth, 12, 1)
vrec := BIN2W(RIGHT(memwidth,2))
IF ( vtype $ CHR(195) + CHR(204), memcount := 14 + vrec, memcount := 22 )
FSEEK( memhandle, memcount, pSEEK_CURRENT )
IF LEFT( vname, 1) # "_"
tel++
ttemp1 := vname //LEFT( vname + SPACE(10), 10)
ttemp2 := TYPE(vname)
ttemp3 := IF(TYPE(vname) = pCHARACTER, "[" + &vname. + "]", strvalue( &vname.) )
DO CASE
CASE TYPE(vname) = pCHARACTER
bytes += ( atemp := LEN( &vname. ) )
CASE TYPE(vname) = pNUMERIC
bytes += ( atemp := 9 )
CASE TYPE(vname) = pLOGICAL
bytes += ( atemp := 2 )
CASE TYPE(vname) = pDATE
bytes += ( atemp := 9 )
OTHERWISE
bytes += ( atemp := 0 )
ENDCASE
/* SUPPRESS DB AND FTP INFORMATION : don't want to mention secret password etc.... '*/
IF AT('PW', UPPER(ttemp1)) > 0 .OR. ;
AT('USER', UPPER(ttemp1)) > 0 .OR. ;
AT('SITE', UPPER(ttemp1)) > 0 .OR. ;
AT('HOST', UPPER(ttemp1)) > 0 .OR. ;
AT('PASW', UPPER(ttemp1)) > 0 .OR. ;
AT('DB', UPPER(ttemp1)) > 0
ELSE
? '<tr>'
? '<td style="text-align:right;">' + TRANSFORM( tel, "999") + '</td><td style="text-align:right;">' + TRANSFORM( atemp, "9999999") + '</td><td>' + ttemp1 + '</td><td>' + ttemp2 + '</td><td>' + substr(ttemp3,1,100) + '</td>'
? '</tr>'
ENDIF
ENDIF
ENDDO
? '<tr><td bgcolor="#00ff00" colspan=2 style="text-align:right;">' + TRANSFORM( bytes, "9,999,999") + '</td><td bgcolor="#00ff00" colspan=3>Totaal</td></tr>'
? "</table>"
FCLOSE( memhandle )
This will surely help you a bit....
Serge