How to include specific items like a record or line number, in your error handler

General Help regarding HMG, Compilation, Linking, Samples

Moderator: Rathinagiri

HGAutomator
Posts: 202
Joined: Thu Jul 16, 2020 5:42 pm
DBs Used: DBF

How to include specific items like a record or line number, in your error handler

Post 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?
User avatar
AUGE_OHR
Posts: 2117
Joined: Sun Aug 25, 2019 3:12 pm
DBs Used: DBF, PostgreSQL, MySQL, SQLite
Location: Hamburg, Germany

Re: How to include specific items like a record or line number, in your error handler

Post 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 )
have fun
Jimmy
HGAutomator
Posts: 202
Joined: Thu Jul 16, 2020 5:42 pm
DBs Used: DBF

Re: How to include specific items like a record or line number, in your error handler

Post 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,
HGAutomator
Posts: 202
Joined: Thu Jul 16, 2020 5:42 pm
DBs Used: DBF

Re: How to include specific items like a record or line number, in your error handler

Post 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.
User avatar
serge_girard
Posts: 3420
Joined: Sun Nov 25, 2012 2:44 pm
DBs Used: 1 MySQL - MariaDB
2 DBF
Location: Belgium
Contact:

Re: How to include specific items like a record or line number, in your error handler

Post 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
There's nothing you can do that can't be done...
User avatar
AUGE_OHR
Posts: 2117
Joined: Sun Aug 25, 2019 3:12 pm
DBs Used: DBF, PostgreSQL, MySQL, SQLite
Location: Hamburg, Germany

Re: How to include specific items like a record or line number, in your error handler

Post 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
have fun
Jimmy
User avatar
mol
Posts: 3825
Joined: Thu Sep 11, 2008 5:31 am
Location: Myszków, Poland
Contact:

Re: How to include specific items like a record or line number, in your error handler

Post 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
User avatar
serge_girard
Posts: 3420
Joined: Sun Nov 25, 2012 2:44 pm
DBs Used: 1 MySQL - MariaDB
2 DBF
Location: Belgium
Contact:

Re: How to include specific items like a record or line number, in your error handler

Post by serge_girard »

Marek, Me too !

Happens happily very seldom!

Serge
There's nothing you can do that can't be done...
HGAutomator
Posts: 202
Joined: Thu Jul 16, 2020 5:42 pm
DBs Used: DBF

Re: How to include specific items like a record or line number, in your error handler

Post 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
HGAutomator
Posts: 202
Joined: Thu Jul 16, 2020 5:42 pm
DBs Used: DBF

Re: How to include specific items like a record or line number, in your error handler

Post 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
Post Reply