I think this is a difficult topic and many people will obviously have their own solution to this problem. And this is not really an RPG only topic. This problem exists in every programming language (I have encountered so far).
What to do when an error can occur?
Should I catch/monitor the error? Should I log the error? Should I do anything?
And especially the last question is the one where most people will say: "Of course you need to do something!" But this is not true at all. If you cannot handle the error in the location you are (in your program or stack) then you probably should not do anything and let the error "bubble up" to the next level in the call stack where it might be handled in a better way.
Log and Throw
This is a common thing we have learned is a "NoNo". But this is where our IBM i platform (especially the ILE environment) is different than other platforms:
Everything is already logged in the job log!
Everything? Probably not. But it is enough to say that we don't need any additional logging strategy for errors. That does not mean that we never need any additional logging at all. More log statements may better show the flow inside the program and other log frameworks may use another medium beside the job log. But that is another topic.
But "Log and throw" cannot be excluded on IBM i as every escape message is automatically logged in the job log and we may want to communicate to the caller a specific message or condition. So we may rethrow the caught escape message with a specific message from our own message file.
Sending an Escape Message
Sending a message from a message file does not have to be complicated. It can be as easy as calling a single procedure.
message_file_escape(*omit : 'DMOMSGFILE' : 'DMO0010');
Now the caller can use a monitor block to catch that escape message and analyze it.
/include psds.rpginc /include qusec.rpginc ... dcl-ds errorCode likeds(qusec) inz; ... monitor; demo_persist(data); on-error; if (exception = 'DMO0010') sendValidationErrorResponse(); else; // cannot handle any other error here => send it to the next call stack entry message_resendEscapeMessage('' : errorCode); endif; endmon;
Escape Messages only for real Errors
When you want to communicate something back to the caller which is not an error then don't use an escape message. It is way more effecient to use something like a constant as a return value than an escape message to do that. Handling escape messages is much more expensive than just checking a value.
And document what the user can expect! If a program or procedure sends an escape message in a certain situation then write it down so that the user of the program or procedure can handle it if possible (or send it further up the stack).
The same goes for web service endpoints: document what the web client can expect!
Happy error handling!