This is the part of the trade used most and taught least. A program that does not work leaves far more traces than whoever is looking usually checks.
Reading the error
When an RPG program fails, the job log contains two separate things, and you need both.
The message. RNQ are exceptions that stop and wait for an answer, RNX those that end
the program. MCH are machine-level errors — index out of range, a numeric field holding
something that is not numeric.
The call stack. It gives the program, the procedure and the statement number. It is the information that leads straight to the spot, and it is ignored nearly every time.
DSPJOBLOG JOB(123456/JSMITH/CLOSE)
On a job still active, the stack is seen with WRKJOB, option 11.
Tip
compiling with OPTION(*SRCSTMT) makes the number in the message the source
line number, not an internal number to convert back. It is a parameter that costs
nothing, and without it half the error's information is wasted. Worth making the default
for everything you compile.
Errors handled by the program
A program can notice an error itself instead of dying. Two ways.
MONITOR, the modern form, covering a block:
monitor;
chain (number) orders;
if not %found(orders);
// record absent: an expected case
endif;
on-error;
// any error inside the block
status = 'Error reading orders';
endmon;
*PSSR, the program's error subroutine, catching whatever was not handled elsewhere
and acting as the last net before the end.
Warning
a *PSSR that merely does return turns a failure into silence. The program
ends, the job appears to have finished normally, and the data was not written. It is how
closes that "went fine" and left the file half done come about. Whatever the *PSSR does,
it must leave a trace: a message on a queue, a line in a log file, a return code the
caller checks.
The debugger
The ILE debugger works on source, provided the program was compiled with the necessary information:
CRTBNDRPG PGM(PRODLIB/INVOICES) DBGVIEW(*SOURCE)
*SOURCE shows the original source, *LIST the listing after copy members and SQL
precompilation have been expanded — which is what you need when the problem is inside a
/COPY or inside an EXEC SQL.
STRDBG PGM(PRODLIB/INVOICES) UPDPROD(*YES)
Then you set a breakpoint (F6 on the line), run the program, and stop there: F10 steps, F12 resumes, F11 shows the value of the variable under the cursor.
Warning
UPDPROD(*YES) is what lets you work against production files, and it should
be typed deliberately. In debug the statements really run: if the program writes, the
record is written. Testing against a test library, with OVRDBF pointing at test data, is
the difference between a debugging session and an incident.
The job that is not yours
The most frequent case and the least known: the problem is in a batch job that starts at night, and the debugger has to be attached from outside.
STRSRVJOB JOB(123456/JSMITH/CLOSE)
STRDBG PGM(PRODLIB/CLOSE) UPDPROD(*YES)
From then on the debug commands apply to that job: set the breakpoints, release the job, and
stop at the right place inside the real processing. You finish with ENDDBG and
ENDSRVJOB.
Tip
for a scheduled job that only fails at night, the route is to hold the schedule
entry, submit the job by hand to a held queue, attach with STRSRVJOB and then release it.
You get the same job, in the same environment, with somebody watching.
The dump
When the problem will not reproduce, the snapshot remains:
dump(a);
DSPJOB option 11 on an active job, or the QPPGMDMP spooled file produced by a program
that ended in error, show the contents of every variable at the moment of failure. On an
error that happens once a month it is the only information you have.
The three things that settle most cases
Look at the first error, not the last. In a long job log the final messages describe a program already in trouble. The message that explains is the first serious one.
Check that the object matches the source. Before reading the code line by line,
DSPOBJD ... DETAIL(*SERVICE) says when the object was compiled and from which source. An
hour lost hunting a bug in code that is not the code running is an experience you have
once.
Look at the environment before the program. The job's library list, active overrides, activation group, ASP group. A sizeable share of failures that look like programming failures are environment failures, and the program is innocent.
Comments
No comments yet. Be the first to comment!
You need an account to comment. Log in · Sign up