エンド・ユーザーにリリースした適用業務の実行において何か予測できなかったエラーが
発生したときに、エラー・メッセージが報告されていても真のエラー原因を掴むことが
できずに悩んだことはないだろうか ?
真のエラー原因を突き止めるためにデータを調べたり、ダンプ解析をしていたのでは
時間がかかってしまう。
特に弊社のようにソフトウェア・パッケージとして配布しているプログラムで問題が
発生したときは調査に時間をかけることはあまりできない。
ここで紹介する CLP は単に SBMJOB するだけのCLプログラムであるが
想定できなかった、すべてのエラーの発生に備えて情報が収集できるようになっている。
最初に CLPソースの全容を紹介する。
0001.00 PGM PARM(&PFRTIME &TIMEDEF) 0002.00 /*-------------------------------------------------------------*/ 0003.00 /* STRPFRMON : パフォーマンス・モニター開始 */ 0004.00 /*-------------------------------------------------------------*/ 0005.00 DCL VAR(&PFRTIME) TYPE(*DEC) LEN(5 0) 0006.00 DCL VAR(&TIMEDEF) TYPE(*DEC) LEN(5 0) 0007.00 DCL VAR(&MSG) TYPE(*CHAR) LEN(80) 0008.00 DCL VAR(&MSGID) TYPE(*CHAR) LEN(7) 0009.00 DCL VAR(&MSGDTA) TYPE(*CHAR) LEN(132) 0010.00 DCL VAR(&MSGID) TYPE(*CHAR) LEN(7) 0011.00 DCL VAR(&MSGF) TYPE(*CHAR) LEN(10) 0012.00 DCL VAR(&MSGFLIB) TYPE(*CHAR) LEN(10) 0013.00 DCL VAR(&JOB) TYPE(*CHAR) LEN(10) 0014.00 DCL VAR(&USER) TYPE(*CHAR) LEN(10) 0015.00 DCL VAR(&NBR) TYPE(*CHAR) LEN(6) 0016.00 DCL VAR(&TYPE) TYPE(*CHAR) LEN(1) 0017.00 DCL VAR(&SEV) TYPE(*DEC) LEN(2 0) 0018.00 MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR)) 0019.00 0020.00 RTVJOBA JOB(&JOB) USER(&USER) NBR(&NBR) TYPE(&TYPE) 0021.00 SBMJOB CMD(CALL PGM(ASNET.COM/PFRMON) PARM(&PFRTIME + 0022.00 &TIMEDEF)) JOB(PFRMONTOR) + 0023.00 JOBQ(ASNET.COM/ENTPRSSVR) 0024.00 0025.00 ERROR: RCVMSG MSGTYPE(*LAST) RMV(*NO) MSG(&MSG) + 0026.00 MSGDTA(&MSGDTA) MSGID(&MSGID) SEV(&SEV) + 0027.00 MSGF(&MSGF) MSGFLIB(&MSGFLIB) 0028.00 SNDMSG: 0029.00 IF COND(&TYPE *EQ '0') THEN(DO) /* バッチ JOB */ 0030.00 IF COND(&SEV *GE 10) THEN(DO) 0031.00 DMPCLPGM 0032.00 SNDPGMMSG MSG(' ダンプを QEZDEBUG に出力しました。 ') + 0033.00 TOMSGQ(*SYSOPR) 0034.00 SNDPGMMSG MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) + 0035.00 MSGDTA(&MSGDTA) TOMSGQ(*SYSOPR) 0036.00 SNDPGMMSG MSG('STRPFRMON- ジョブ ' *CAT &JOB *TCAT + 0037.00 '/' *CAT &USER *TCAT '/' *CAT &NBR + 0038.00 *TCAT + 0039.00 ' で次のエラーが発生しました。 ') + 0040.00 TOMSGQ(*SYSOPR) 0041.00 ENDDO 0042.00 ELSE CMD(DO) 0043.00 SNDPGMMSG MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) + 0044.00 MSGDTA(&MSGDTA) TOMSGQ(*SYSOPR) + 0045.00 MSGTYPE(*COMP) 0046.00 ENDDO 0047.00 ENDDO /* バッチ JOB */ 0048.00 ELSE CMD(DO) /* 対話式 */ 0049.00 SNDPGMMSG MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) + 0050.00 MSGDTA(&MSGDTA) TOMSGQ(*TOPGMQ) + 0051.00 MSGTYPE(*DIAG) 0052.00 ENDDO /* 対話式 */ 0053.00 ENDPGM
【 解説 】
最初に
0020.00 RTVJOBA JOB(&JOB) USER(&USER) NBR(&NBR) TYPE(&TYPE)
によって、このジョブのジョブ情報とジョブのタイプを調べている。
&TYPE が 0 であれば、このジョブはバッチ・ジョブとして実行されているし、
&TYPE が 1 であれば、このジョブは対話式ジョブとして実行されていることがわかる。
次に
0018.00 MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR))
によって、例外的なエラーが発生したときは、すべて制御は ERROR: タグへジャンプする
また、
0021.00 SBMJOB CMD(CALL PGM(ASNET.COM/PFRMON) PARM(&PFRTIME + 0022.00 &TIMEDEF)) JOB(PFRMONTOR) + 0023.00 JOBQ(ASNET.COM/ENTPRSSVR)
の直後には RETURN 命令がないことからわかるように、正常に処理された場合でも
完了メッセージを受信して表示することが必要であるので、やはり制御は ERROR: タグに
渡される。
>ERROR: タグでは RCVMSG によってメッセージを受信しているのであるが
メッセージ・データ (&MSGDTA) とメッセージ・ファイル( &MSGF, &MSGFLIB) と
メッセージ識別コード (&MSGID) の受信を主体としてメッセージを検索している。
これらを組み合わせてから SNDPGMMSG を行うとローレベル・メッセージと
メッセージ識別までをできるからである。
含むすべてのメッセージ情報を完全な形で復元して、メッセージとして出力することが
単にエラー・メッセージを出力するたけであれば、エラーの詳細までを知ることができないからである。
また、この CLP がバッチ・ジョブとして実行されているときは、
0031.00 DMPCLPGM 0032.00 SNDPGMMSG MSG(' ダンプを QEZDEBUG に出力しました。 ') + 0033.00 TOMSGQ(*SYSOPR)
とあるように実行時のダンプが OUTQ: QEZDEBUG に出力されるので、エラーが発生したときの
CLP 内の変数の値やエラー・ステートメントも後で調べることができるようになっている。
もちろん、
0036.00 SNDPGMMSG MSG('STRPFRMON- ジョブ ' *CAT &JOB *TCAT + 0037.00 '/' *CAT &USER *TCAT '/' *CAT &NBR + 0038.00 *TCAT + 0039.00 ' で次のエラーが発生しました。 ') + 0040.00 TOMSGQ(*SYSOPR)
にあるように、エラー・メッセージだけでなく、この CLP 自身の名前も通知しておくことも必要である。
簡単な処理であるので、エラーも発生することなく動作するであろうと期待していた CLP でも
このようにしっかりとエラー・モニターしておけば障害のときの調査がよりわかりやすく
短時間のうちに調査することができるようになる。
プログラムの品質の向上のためにエラー・モニターのしっかりした体制を作っておきたいものである。