Hi all,
Do you have any advice about putting an error handling routine in a library function? I'd like to take a lot of redundant code out of ALL of my programs and "library-ize" it for simplification and ease of upgrading the routine to handle more and more issues.
But how do you handle the variety of different things you may encounter - file sharing errors, index issues, conversion errors, printers not online and all sorts of other errors - when AFTER being trapped, they may need to do different things in different calling programs? OR is it better method to just display a window describing the error, possibly logging it somewhere in a file and then return to the calling program with a call to exit the program?
What do you do? Is your error handling routine in a library?
Thanks!
-- Susan
Error Handing Routine in a library
Moderators: Susan Smith, admin, Gabriel
-
- Posts: 717
- Joined: Sun Aug 10, 2008 4:24 am
- Location: Southern California
I've used a library as an error trap routine for a number of years. However, since I'm my own primary customer more and more in recent years I've been shutting off the function library error trapping.
The problems that I see with this approach include:
1. The program name that defaults when you ar in the library is the name of the library. Not so much of a problem if you remember to pass the name of the calling ptogram to the error library as a paramenter
2. The retry function does not work as easily, you need to have the error routine end with an FNEND, pass a variable back to your calling program and then have the subroutine that was triggered by the error decide what to do
3. Line number and error number need to be passed as parameters to the library for the same reason as the program name. It would not hurt to do a STATUS stacks or STATUS all and drop it to a file/log for information.
4. You need to decide whether you want the user to be able to kill the process in the library or not, possibly writing a PROC file to disk that it can be chained to to bring the user back to the proper menu position.
In my library I did insert a function call to automatically email me with a message that an error had occured and attached a copy of the error ;log for that user. I used David Blankenship's EMAIL MONITOR to do this. A nice touch because often a user figured they had messed up and would not call with an error so I never knew.
It is much easier to debug a program WITHOUT an automatic library call for error trapping. The program stops right where the error is and you can view the parameter values (Something you cannot easily do from a library). For example, if a file is being read by key and you get a nokey error you need to F9 back to the original program and line number to see what the key was supposed to be before you can try to understand why it did not exist and errorred. Stopping at that point without the library makes it far easier to debug.
The problems that I see with this approach include:
1. The program name that defaults when you ar in the library is the name of the library. Not so much of a problem if you remember to pass the name of the calling ptogram to the error library as a paramenter
2. The retry function does not work as easily, you need to have the error routine end with an FNEND, pass a variable back to your calling program and then have the subroutine that was triggered by the error decide what to do
3. Line number and error number need to be passed as parameters to the library for the same reason as the program name. It would not hurt to do a STATUS stacks or STATUS all and drop it to a file/log for information.
4. You need to decide whether you want the user to be able to kill the process in the library or not, possibly writing a PROC file to disk that it can be chained to to bring the user back to the proper menu position.
In my library I did insert a function call to automatically email me with a message that an error had occured and attached a copy of the error ;log for that user. I used David Blankenship's EMAIL MONITOR to do this. A nice touch because often a user figured they had messed up and would not call with an error so I never knew.
It is much easier to debug a program WITHOUT an automatic library call for error trapping. The program stops right where the error is and you can view the parameter values (Something you cannot easily do from a library). For example, if a file is being read by key and you get a nokey error you need to F9 back to the original program and line number to see what the key was supposed to be before you can try to understand why it did not exist and errorred. Stopping at that point without the library makes it far easier to debug.
-
- Posts: 717
- Joined: Sun Aug 10, 2008 4:24 am
- Location: Southern California
These are good points, George. With the point about debugging programs, I usually use ON ERROR SYSTEM when I'm debugging as I know it's almost impossible to debug across libraries. But I really want to TRY to create a central error-handling routine, unless it's really a bad idea. Perhaps I should check for certain errors that the routine is meant to handle and others can remain in the calling program instead of library-izing it ALL. There has to be a way to make a very complete elegant error-handing routine that I can use in every program. And of course I've learned enough from you (George) that if it can "function" in a library (pun intended), then that's usually the way to go. But maybe not this time?
I was thinking of having a minimal stub routine in all of the calling programs that sets up all of the variables to pass to the error-handling function (maybe in an array with the first column being the description of the data and the 2nd column being the data such as program name, err, line, etc. I haven't thought about that part much yet.) Then in the function, I'd add to an error log file, possibly display a message to the user about what has happened (if I know), and perhaps have Email monitor send me a message with an attached file that includes all of those values I passed to the function, along with additional information such as STATUS ALL in it. I figured that I could parse the program line on which the error happened to get some more information. I could EXECUTE "LIST "&str$(line)&" >error.line" and then read that back in and analyze it. At that point, the error routine can decide if the calling program needs to exit, continue, or whatever, and send THAT result back to the calling program to deal with.
At least that is my hope. I am going to be implementing such a sweeping set of program changes later this year that I'm anticipating more errors than usual and I would really love to monitor the results. Like you have found, users do NOT like to report errors to me if they can just "get out of them". But we all know that sooner or later, some of those unreported errors can result in data instability (or at least "mystery issues") and when I ask people if they have got any errors, they either can't remember OR they don't want to tell me that they bailed out of the program to solve their problem, so they say no.
When you (George, as well as the rest of you) do your error handling, do you present the user with explanations of the errors (like from the errors.txt files)? Or do you hide that part from them?
Does anyone else use a library to handle errors? If not, why not? Do you have the same issues as George, or are there other reasons? If you aren't using a library, are you duplicating the same error-handling code in every single program then? I guess I'm looking for the best way to have an elegant error-handler that doesn't have to put a ton of code in every program and I'd LIKE it to be a library so I can tweak ONE error handler and have it instantly usable by all programs.
-- Susan
I was thinking of having a minimal stub routine in all of the calling programs that sets up all of the variables to pass to the error-handling function (maybe in an array with the first column being the description of the data and the 2nd column being the data such as program name, err, line, etc. I haven't thought about that part much yet.) Then in the function, I'd add to an error log file, possibly display a message to the user about what has happened (if I know), and perhaps have Email monitor send me a message with an attached file that includes all of those values I passed to the function, along with additional information such as STATUS ALL in it. I figured that I could parse the program line on which the error happened to get some more information. I could EXECUTE "LIST "&str$(line)&" >error.line" and then read that back in and analyze it. At that point, the error routine can decide if the calling program needs to exit, continue, or whatever, and send THAT result back to the calling program to deal with.
At least that is my hope. I am going to be implementing such a sweeping set of program changes later this year that I'm anticipating more errors than usual and I would really love to monitor the results. Like you have found, users do NOT like to report errors to me if they can just "get out of them". But we all know that sooner or later, some of those unreported errors can result in data instability (or at least "mystery issues") and when I ask people if they have got any errors, they either can't remember OR they don't want to tell me that they bailed out of the program to solve their problem, so they say no.
When you (George, as well as the rest of you) do your error handling, do you present the user with explanations of the errors (like from the errors.txt files)? Or do you hide that part from them?
Does anyone else use a library to handle errors? If not, why not? Do you have the same issues as George, or are there other reasons? If you aren't using a library, are you duplicating the same error-handling code in every single program then? I guess I'm looking for the best way to have an elegant error-handler that doesn't have to put a ton of code in every program and I'd LIKE it to be a library so I can tweak ONE error handler and have it instantly usable by all programs.
-- Susan
Remember that once you are in the library the line that caused the error is not available so your sub-routine in the program needs to send the line to your log before engaging the function.
When creating the log use the double hreater than so the information gets appended rather than replaces the log file >>
In some of my programs I have played around with using the ERRORS.txt file and a MSGBOX to display the descripton of the error. Not sure yet whether this is a good thinh to show users or not. I'd be interested in other's views of this.
60700 DEF LIBRARY FNERRTXT(ERNO)
60710 LIBRARY ENV$("PD")&"vol002\fnsnap.dll": FNGETHANDLE
60715 IF NOT ESC THEN EXECUTE "PROC *:vol002\tt"
60720 OPEN #(ERRTXT:=FNGETHANDLE): "name="&ENV$("PD")&"vol002\errors.txt",DISPLAY,INPUT
60730 LET X$="Error code "&CNVRT$("PIC(####)",ERNO)
60740 DIM ER$*2000
60750 LINPUT #ERRTXT: ER$ EOF ZERRTXT
60760 IF NOT X$=ER$(1:15) THEN GOTO 60750
60770 LET MSGBOX(SREP$(ER$(17:INF),"\n",CRLF$),"Error Description")
60780 ZERRTXT: CLOSE #ERRTXT: !:
LET ERRTXT=0
60790 FNEND
When creating the log use the double hreater than so the information gets appended rather than replaces the log file >>
In some of my programs I have played around with using the ERRORS.txt file and a MSGBOX to display the descripton of the error. Not sure yet whether this is a good thinh to show users or not. I'd be interested in other's views of this.
60700 DEF LIBRARY FNERRTXT(ERNO)
60710 LIBRARY ENV$("PD")&"vol002\fnsnap.dll": FNGETHANDLE
60715 IF NOT ESC THEN EXECUTE "PROC *:vol002\tt"
60720 OPEN #(ERRTXT:=FNGETHANDLE): "name="&ENV$("PD")&"vol002\errors.txt",DISPLAY,INPUT
60730 LET X$="Error code "&CNVRT$("PIC(####)",ERNO)
60740 DIM ER$*2000
60750 LINPUT #ERRTXT: ER$ EOF ZERRTXT
60760 IF NOT X$=ER$(1:15) THEN GOTO 60750
60770 LET MSGBOX(SREP$(ER$(17:INF),"\n",CRLF$),"Error Description")
60780 ZERRTXT: CLOSE #ERRTXT: !:
LET ERRTXT=0
60790 FNEND
-
- Posts: 717
- Joined: Sun Aug 10, 2008 4:24 am
- Location: Southern California
I know what you mean about displaying the error msg description to users. Some users get a little too "Sherlock Holmes" in trying to diagnose their own problems, which is rarely good as far as I can see. Or they decide that it doesn't sound serious, so they bail out of the BR program and don't notify me.
I think I'd be happy if my error routine could:
1) receive all of the error details that I can send to it from the calling program
2) Display the fact (to the user) that there WAS an error in a msgbox and ask the user to notify me
3) log the error information in a file
4) Return to the calling program and gracefully exit.
Now maybe this wouldn't be appropriate all the time, but it seems to me the MOST of the time, I'd really want the program to exit when there is an error, rather than continue. Is that your experience as well? The error routine I have now is in every program and it has the option to display the error text, the line that the error occurred on, and then the user can choose to retry, continue or abort the program. But none of this is in a library...or even in a function. I have an ON ERROR GOTO ERRCOND line at the top of every program. In this subroutine, 90% of the time the user HAS to choose to abort because most errors will keep appearing if they choose retry and if they choose "continue", often a secondary error will result if the first one isn't solved. So perhaps aborting the calling program gracefully is the best default action.
If there are errors like 4272 or 4270, they can be handled in the original program with NOKEY or EOF traps. I already do that. An example of this (the NOKEY err) might be if you were printing a report and needed to go to a file to retrieve a name or description. I usually default that description/name field to "Not on file" before I do the "read #X,key=..." and then the read statement replaces it with the "real" data. If there is a NOKEY, I just continue and the user can figure it out for themselves when they see that Customer #1000's name is listed as "Not on file" on the report.
If the user is posting or doing some other sort of file update and gets an error, I can roll back the changes before exiting the program (I generally make temporary copies of files before I begin so I can copy the files back and start over if need be. It's not a true transactional rollback however.)
Looking forward to hearing more about what the rest of you are doing for error trapping. This seems to be a good discussion to have. I'm sure I can learn from everybody else's ideas and I hope you can too.
-- Susan
I think I'd be happy if my error routine could:
1) receive all of the error details that I can send to it from the calling program
2) Display the fact (to the user) that there WAS an error in a msgbox and ask the user to notify me
3) log the error information in a file
4) Return to the calling program and gracefully exit.
Now maybe this wouldn't be appropriate all the time, but it seems to me the MOST of the time, I'd really want the program to exit when there is an error, rather than continue. Is that your experience as well? The error routine I have now is in every program and it has the option to display the error text, the line that the error occurred on, and then the user can choose to retry, continue or abort the program. But none of this is in a library...or even in a function. I have an ON ERROR GOTO ERRCOND line at the top of every program. In this subroutine, 90% of the time the user HAS to choose to abort because most errors will keep appearing if they choose retry and if they choose "continue", often a secondary error will result if the first one isn't solved. So perhaps aborting the calling program gracefully is the best default action.
If there are errors like 4272 or 4270, they can be handled in the original program with NOKEY or EOF traps. I already do that. An example of this (the NOKEY err) might be if you were printing a report and needed to go to a file to retrieve a name or description. I usually default that description/name field to "Not on file" before I do the "read #X,key=..." and then the read statement replaces it with the "real" data. If there is a NOKEY, I just continue and the user can figure it out for themselves when they see that Customer #1000's name is listed as "Not on file" on the report.
If the user is posting or doing some other sort of file update and gets an error, I can roll back the changes before exiting the program (I generally make temporary copies of files before I begin so I can copy the files back and start over if need be. It's not a true transactional rollback however.)
Looking forward to hearing more about what the rest of you are doing for error trapping. This seems to be a good discussion to have. I'm sure I can learn from everybody else's ideas and I hope you can too.
-- Susan
I typically write error info to a file. The info contains the program name, error number, line number, date and time and user. I can then look at the file and see what is going on.
The operator is advised of the error and given the option of calling me or pressing enter to continue and exit the program. Sometimes there is code that will evaluate the error and allow the operator to try again. Mostly I exit the program.
The operator is advised of the error and given the option of calling me or pressing enter to continue and exit the program. Sometimes there is code that will evaluate the error and allow the operator to try again. Mostly I exit the program.