Inter­cep­tion d’une erreur non prévue

Inter­cep­tion d’une erreur non prévue

lun 11 février 2019 0 Par Ibmiiste

Vous recon­nais­sez-vous sur la pho­to ? C’est lors de votre der­nier plan­tage en pro­duc­tion, le fameux « Excep­tion and Error Hand­ling » d’IBM, Vous avez l’u­ti­li­sa­teur au télé­phone qui vous dit : 

« J'ai eu un plantage! 
- OK, qu'avez-vous fait?
- l'écran m'a demandé de répondre C D G ou F.
- Et qu'avez-vous saisi?
- J'ai saisi C »; vous dit-il fièrement.
Vous, après le coup de téléphone.

Pour vous aider à ne plus vous retrou­ver face à cette situa­tion, voi­ci quelques idées pour maî­tri­ser l’in­ter­cep­tion de ces plan­tages et une sous-pro­cé­dure pour expri­mer ces erreurs. 

Les idées

CLP, CLLE

Le code ci-des­sous pla­cé dans une sous-rou­tine per­met d’in­ter­cep­ter et géné­rer des infor­ma­tions néces­saires à l’analyse de l’erreur sans « plan­ter » le tra­vail. La sous-pro­cé­dure Gest_erreur sert à com­pi­ler les infor­ma­tions et à aver­tir qui de droit. Elle sera expli­quée plus loin dans cet article. 

PGM
DCL VAR(&PGM) TYPE(*CHAR) LEN(10) VALUE('TESTPGM1')
CPYF FROMFILE(TESTFILE) TOFILE(TESTFILEH) MBROPT(*ADD)
MONMSG MSGID(CPF0000) EXEC(CALLSUBR SUBR(ERROR))
----
----
/*==========================================================*/
SUBR(ERROR)
DMPCLPGM
CALLPRC PRC(GEST_ERREUR)
ENDSUBR
/*==========================================================*/
ENDPGM

Figure 1

Nous pou­vons déci­der d’ar­rê­ter le pro­gramme et redon­ner le contrôle à l’appelant en dépla­çant l’in­ter­cep­tion d’er­reur en fin de programme.

         PGM PARM(&BIB &NEWPROP &CUROWNAUT)
         DCL VAR(&BIB) TYPE(*CHAR) LEN(10)
         DCL VAR(&NEWPROP) TYPE(*CHAR) LEN(10)
         DCL VAR(&CUROWNAUT) TYPE(*CHAR) LEN(10)
         DCLF FILE(DSPOBJDL)
         MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERREUR))
         DSPOBJD OBJ(&BIB/*ALL) OBJTYPE(*ALL) +
                 OUTPUT(*OUTFILE) OUTFILE(QTEMP/DSPOBJDL)
LECTURE: RCVF
         MONMSG MSGID(CPF0864) EXEC(GOTO CMDLBL(FIN))
         CHGOBJOWN OBJ(&BIB/&ODOBNM) OBJTYPE(&ODOBTP) +
                   NEWOWN(&NEWPROP) CUROWNAUT(&CUROWNAUT)
         RETURN
ERREUR:  DMPCLPGM
         CALLPRC PRC(GEST_ERREUR)
FIN:     ENDPGM

Figure 2

RPG, RPG ile

Carte H ou spé­ci­fi­ca­tions de contrôles

Pour avoir les meilleurs chances pos­sibles de notre côté, nous allons amen­der les spé­ci­fi­ca­tions de contrôles (Fig. 3):

  1. L’option *srcstmt est très utile, lors d’une remon­tée d’erreur, la ligne indi­quée en erreur est le numé­ro de ligne du source à la place de celle de lis­ting de compilation. 
  2. Le mot debug n’est pas obli­ga­toire, dans ce cas la com­mande dump prend l’option (a) : dump(a).

Plu­sieurs méthodes d’interception d’erreur sont pos­sibles : *PSSR ou le groupe MONITOR.

*PSSR

La sous-rou­tine *PSSR est appe­lé quand une erreur non inter­cep­tée se pro­duit. Il est pré­fé­rable d’u­ti­li­ser l’o­pé­ra­tion MONITOR dans la pro­gram­ma­tion moderne. *PSSR est à uti­li­ser dans le cas de pro­gramme uti­li­sant le cycle (GOTO ou les tags). Tou­te­fois ces pro­grammes existent et fonc­tionnent tou­jours, il est donc néces­saire de connaître ce moyen.

 H Option(*srcstmt) debug
            | | | | | | | | | | | | | |
 c      *pssr BEGSR
 c            dump
 c            callp gest_erreur()
 c            ENDSR

Figure 3

Groupe MONITOR

Aujourd’­hui, la méthode pré­co­ni­sée par IBM est le groupe MONITOR.

 hdebug(*yes) datfmt(*eur) bnddir('SERVICE') option(*srcstmt)
          | |
   /free
      monitor;
           | |
           | |
      on-error;
        dump;
        gest_erreur();
      endmon;

Mais vous ne pou­vez pas uti­li­ser Moni­tor quand des opé­ra­tions tel que goto existent.

Figure 4

Expres­sion des anomalies

Après avoir vu com­ment inter­cep­ter les erreurs, nous allons voir GEST_ERREUR qui gère la res­ti­tu­tion des infor­ma­tions qui va vous per­mettre d’a­na­ly­ser le pro­blème ren­con­tré par l’utilisateur. 

L’ou­til est consti­tué de 2 sous-pro­cé­dures, fig.5 vous montre le source de liage. 

             STRPGMEXP  PGMLVL(*CURRENT)
                EXPORT     SYMBOL(GEST_ERREUR)
                EXPORT     SYMBOL(MAILERR)
             ENDPGMEXP      

Figure 5

Gest_erreur

La sous-pro­cé­dure gest-erreur pré­sente 2 fonc­tion­ne­ments selon que le tra­vail est inter­ac­tif ou batch.

Gest_erreur com­porte trois étapes. 

  1. Il édite un résu­mé de l’erreur. 
  2. Si le tra­vail est un batch, il édite l’é­cran sur lequel l’u­ti­li­sa­teur se trou­vait quand l’er­reur a eu lieu.
  3. Il extrait les adresses email de destination.
     h nomain debug
      * Déclaration des fichiers
     fMailInfol2if   e           k disk    USROPN
     FERRORLST  O    e             printer
     F                                     USROPN
     F                                     OFlInd(OverFlow)
      * Déclaration de le PSDS
     d*copy qcpysrc,CPY_PSDS
      *
      * Copie API
      /Copy qcpysrc,STDMSGINFO
      * Programme data structure
     D  HlpText        DS
     D  HlpText01
     D  HlpText02
     D  HlpText03
     D  HlpText04
     D  HlpText05
     D  HlpText06
     D  HlpText07
     D  HlpText08
     D  HlpText09
     D  HlpText10
     D ScreenIn        DS
     D  Row8001                            OverLay(ScreenIn:1)
     D  Row8002                            OverLay(ScreenIn:*Next)
     D  Row8003                            OverLay(ScreenIn:*Next)
     D  Row8004                            OverLay(ScreenIn:*Next)
     D  Row8005                            OverLay(ScreenIn:*Next)
     D  Row8006                            OverLay(ScreenIn:*Next)
     D  Row8007                            OverLay(ScreenIn:*Next)
     D  Row8008                            OverLay(ScreenIn:*Next)
     D  Row8009                            OverLay(ScreenIn:*Next)
     D  Row8010                            OverLay(ScreenIn:*Next)
     D  Row8011                            OverLay(ScreenIn:*Next)
     D  Row8012                            OverLay(ScreenIn:*Next)
     D  Row8013                            OverLay(ScreenIn:*Next)
     D  Row8014                            OverLay(ScreenIn:*Next)
     D  Row8015                            OverLay(ScreenIn:*Next)
     D  Row8016                            OverLay(ScreenIn:*Next)
     D  Row8017                            OverLay(ScreenIn:*Next)
     D  Row8018                            OverLay(ScreenIn:*Next)
     D  Row8019                            OverLay(ScreenIn:*Next)
     D  Row8020                            OverLay(ScreenIn:*Next)
     D  Row8021                            OverLay(ScreenIn:*Next)
     D  Row8022                            OverLay(ScreenIn:*Next)
     D  Row8023                            OverLay(ScreenIn:*Next)
     D  Row8024                            OverLay(ScreenIn:*Next)
     D  Row13201                           OverLay(ScreenIn:1)
     D  Row13202                           OverLay(ScreenIn:*Next)
     D  Row13203                           OverLay(ScreenIn:*Next)
     D  Row13204                           OverLay(ScreenIn:*Next)
     D  Row13205                           OverLay(ScreenIn:*Next)
     D  Row13206                           OverLay(ScreenIn:*Next)
     D  Row13207                           OverLay(ScreenIn:*Next)
     D  Row13208                           OverLay(ScreenIn:*Next)
     D  Row13209                           OverLay(ScreenIn:*Next)
     D  Row13210                           OverLay(ScreenIn:*Next)
     D  Row13211                           OverLay(ScreenIn:*Next)
     D  Row13212                           OverLay(ScreenIn:*Next)
     D  Row13213                           OverLay(ScreenIn:*Next)
     D  Row13214                           OverLay(ScreenIn:*Next)
     D  Row13215                           OverLay(ScreenIn:*Next)
     D  Row13216                           OverLay(ScreenIn:*Next)
     D  Row13217                           OverLay(ScreenIn:*Next)
     D  Row13218                           OverLay(ScreenIn:*Next)
     D  Row13219                           OverLay(ScreenIn:*Next)
     D  Row13220                           OverLay(ScreenIn:*Next)
     D  Row13221                           OverLay(ScreenIn:*Next)
     D  Row13222                           OverLay(ScreenIn:*Next)
     D  Row13223                           OverLay(ScreenIn:*Next)
     D  Row13224                           OverLay(ScreenIn:*Next)
     D  Row13225                           OverLay(ScreenIn:*Next)
     D  Row13226                           OverLay(ScreenIn:*Next)
     D  Row13227                           OverLay(ScreenIn:*Next)
      * Prototypage fonction externe
     d mail_erreur     pr                  extproc(*cl : 'MAILERR')
     d a_program                           like(r_nomobj)
     d a_module                            like(r_nomobj)
     d a_procedure                   60
     d a_statement                         like(r_nomobj)
     d a_mail                       320
      * Prototypage fonctions locales
     d gest_erreur     pr
     d adress_mail     pr           320
     d Comp_Adr        pr           320
     d reference                     10
     d mail            s            320
      * Héritages des types
     d/copy QINHLESRC,INH32766
      * Constantes
      * Fonctions locales
     p gest_erreur     b                   export
     d gest_erreur     pi
      * DS locales
      * Variables locales
     D MsgBack         DS                  LikeDs(RCVM0300) Inz
     D InfoPtr         S               *
     D MsgInfo         DS                  LikeDs(RCVM0300SndRcvInfo)
     D                                     Based(InfoPtr)
     D i               S             10I 0
     D SetMsgKey       S              4    Inz(*ALLx'00')
     D BufferHandle    S             10I 0
     D BytesReturned   S             10I 0
     D DataPtr         S               *
     D CatchScreen     DS                  LikeDS(ScreenIn)
     D                                     Based(DataPtr)
      * Fonction principale
      /free
       Monitor;
       Open ErrorLst;
       Open MailInfol2;
       Write Head;
       ReceiveMsg(  MsgBack
                  : %size(MsgBack)
                  : 'RCVM0300'
                  : '*'
                  : 1
                  : '*PRV'
                  : SetMsgKey
                  : 0
                  : '*SAME'
                  : APIError);
       If MsgBack.ByteAvail > 0;
          MsgText = %SubSt(MsgBack.MsgData:
          MsgBack.LenReplace1 + 1:
          MsgBack.LenMsgReturn);
          HlpText = %SubSt(MsgBack.MsgData:
                           MsgBack.LenReplace1 +
                           MsgBack.LenMsgReturn + 1:
                           MsgBack.LenHelpReturn);
          InfoPtr = %Addr(MsgBack.MsgData)
                    + MsgBack.LenReplace1
                    + MsgBack.LenMsgReturn
                    + MsgBack.LenHelpReturn;
          Program = MsgInfo.ReceivingPgm;
          Module = MsgInfo.ReceivingModule;
          Proced = MsgInfo.ReceivingProcedure;
          Statement = MsgInfo.StateNosReceiving;
          Write Detail;
          If OverFlow;
             Write Head;
             OverFlow = *Off;
          EndIf;
       EndIf;
       BufferHandle = CreateInputBuffer( 27 * 132
                                       : *Omit
                                       : *Omit
                                       : *Omit
                                       : APIError );
       If APIError.BytesAvail = 0;
          BytesReturned = ReadScreen( *Omit
                                    : BufferHandle
                                    : *Omit
                                    : *Omit
                                    : *Omit );
          DataPtr = RetrieveDataPtr( BufferHandle
                                   : *Omit
                                   : *Omit );
          ScreenIn = %SubSt(CatchScreen:1:BytesReturned);
          For i = 1 to BytesReturned;
             If (%SubSt(ScreenIn:i:1) > x'19') And
                (%SubSt(ScreenIn:i:1) < x'40');
                %SubSt(ScreenIn:i:1) = *Blank;
             EndIf;
          EndFor;
          If BytesReturned = 1920;
             Write Screen80;
          Else;
             Write Screen132;
          EndIf;
       EndIf;
       Write Footer;
       mail=adress_mail();
       Close ErrorLst;
       Close MailInfol2;
         mail_erreur(   program
                      : module
                      : proced
                      : statement
                      : mail);
         return;
       On-error *all;
         dsply 'Arrrrgghhhh!!!!';
       endmon;
      /end-free
     p gest_erreur     e
     p adress_mail     b
     d adress_mail     pi           320
      * Variables locales
     d l_Adress_Mail   s            320
      /free
       reference=program;
       setll reference mailinfol2;
       if %equal();
          l_Adress_Mail=Comp_Adr(reference);
       else;
          reference='defaut';
          setll reference mailinfol2;
          if %equal();
             l_Adress_Mail=Comp_Adr(reference);
          endif;
       endif;
       return l_Adress_Mail;
      /end-free
     p adress_mail     e
     p Comp_Adr        b
     d Comp_Adr        pi           320
     d reference                     10
      * Variables locales
     d                 ds
     d l_Adress_Mail                320
     d t_Adress_Mail                 32    dim(10)
     d                                     overlay(l_Adress_Mail)
     d i               s              3  0
      /free
       reset l_adress_mail;
       reade reference mailinfol2;
       i=0;
       dow not %eof();
           i+=1;
           t_adress_mail(i)=AdrMail;
           reade reference mailinfol2;
       enddo;
       return l_adress_mail;
      /end-free
     p Comp_Adr        e

Figure 6

Mai­ler

Mai­ler :

  1. génère la joblog, 
  2. conca­tène le résu­mé, le dump et la joblog,
  3. consti­tue l’é­di­tion sous for­mat pdf,
  4. envoi le pdf par mél. 
             PGM        PARM(&PROGRAM &MODULE &PROCEDURE &ERROR &ADRINFO)
             DCLF       FILE(FGESTERR)
             DCL        VAR(&OBJET) TYPE(*CHAR) LEN(44)
             DCL        VAR(&DEST1) TYPE(*CHAR) LEN(36)
             DCL        VAR(&DEST2) TYPE(*CHAR) LEN(36)
             DCL        VAR(&DEST3) TYPE(*CHAR) LEN(36)
             DCL        VAR(&DEST4) TYPE(*CHAR) LEN(36)
             DCL        VAR(&DEST5) TYPE(*CHAR) LEN(36)
             DCL        VAR(&DEST6) TYPE(*CHAR) LEN(36)
             DCL        VAR(&DEST7) TYPE(*CHAR) LEN(36)
             DCL        VAR(&DEST8) TYPE(*CHAR) LEN(36)
             DCL        VAR(&DEST9) TYPE(*CHAR) LEN(36)
             DCL        VAR(&DEST10) TYPE(*CHAR) LEN(36)
             DCL        VAR(&MSG_ERR) TYPE(*CHAR) LEN(2000)
             DCL        VAR(&JOBTYP) TYPE(*CHAR) LEN(1) /* Type de +
                          travail 0 => Batch 1=> interactif */
/*   Email contact                                                    */
             DCL        VAR(&ADRINFO) TYPE(*CHAR) LEN(320)
/*   PARAMETRE D'APPELS PARAMETRABLE                                  */
             DCL        VAR(&MAILADR) TYPE(*CHAR) LEN(50)
             DCL        VAR(&ADRMAIL) TYPE(*CHAR) LEN(320)
             DCL        VAR(&CMD) TYPE(*CHAR) LEN(500)
             DCL        VAR(&LNG) TYPE(*DEC) LEN(15 5) VALUE(500)
             DCL        VAR(&MSG) TYPE(*CHAR) LEN(512)
             DCL        VAR(&MSGID) TYPE(*CHAR) LEN(7)
             DCL        VAR(&MSGF) TYPE(*CHAR) LEN(10)
             DCL        VAR(&MESSAGE) TYPE(*CHAR) LEN(2000)
             DCL        VAR(&ADRPIECJOI) TYPE(*CHAR) LEN(150)
             DCL        VAR(&SYSTEM) TYPE(*CHAR) LEN(8)
             DCL        VAR(&EMET)    TYPE(*CHAR) LEN(30)
             DCL        VAR(&SUJET)    TYPE(*CHAR) LEN(200)
             DCL        VAR(&PROCEDURE) TYPE(*CHAR) LEN(60)
             CHGVAR     VAR(&PROCED1) VALUE(%SST(&PROCEDURE 1 30))
             CHGVAR     VAR(&PROCED2) VALUE(%SST(&PROCEDURE 31 30))
             CHGVAR     VAR(&DEST1) VALUE('(''' *TCAT %SST(&ADRINFO +
                          1 32) *TCAT ''')')
             IF         COND(%SST(&ADRINFO 33 32) *NE ' ') +
                          THEN(CHGVAR VAR(&DEST2) VALUE('(''' *TCAT +
                          %SST(&ADRINFO 33 32) *TCAT ''')'))
             IF         COND(%SST(&ADRINFO 65 32) *NE ' ') +
                          THEN(CHGVAR VAR(&DEST3) VALUE('(''' *TCAT +
                          %SST(&ADRINFO 65 32) *TCAT ''')'))
             IF         COND(%SST(&ADRINFO 97 32) *NE ' ') +
                          THEN(CHGVAR VAR(&DEST4) VALUE('('''' +
                          *TCAT %SST(&ADRINFO 97 32) *TCAT '''')'))
             IF         COND(%SST(&ADRINFO 129 32) *NE ' ') +
                          THEN(CHGVAR VAR(&DEST5) VALUE('('''' +
                          *TCAT %SST(&ADRINFO 129 32) *TCAT '''')'))
             IF         COND(%SST(&ADRINFO 161 32) *NE ' ') +
                          THEN(CHGVAR VAR(&DEST6) VALUE('('''' +
                          *TCAT %SST(&ADRINFO 161 32) *TCAT '''')'))
             IF         COND(%SST(&ADRINFO 193 32) *NE ' ') +
                          THEN(CHGVAR VAR(&DEST7) VALUE('('''' +
                          *TCAT %SST(&ADRINFO 193 32) *TCAT '''')'))
             IF         COND(%SST(&ADRINFO 224 32) *NE ' ') +
                          THEN(CHGVAR VAR(&DEST8) VALUE('('''' +
                          *TCAT %SST(&ADRINFO 224 32) *TCAT '''')'))
             IF         COND(%SST(&ADRINFO 256 32) *NE ' ') +
                          THEN(CHGVAR VAR(&DEST9) VALUE('('''' +
                          *TCAT %SST(&ADRINFO 256 32) *TCAT '''')'))
             IF         COND(%SST(&ADRINFO 288 32) *NE ' ') +
                          THEN(CHGVAR VAR(&DEST10) VALUE('('''' +
                          *TCAT %SST(&ADRINFO 288 32) *TCAT '''')'))
             CHGVAR     VAR(&ADRMAIL) VALUE(&DEST1)
             IF         COND(&DEST2 *NE ' ') THEN(CHGVAR +
                          VAR(&ADRMAIL) VALUE(&ADRMAIL *BCAT &DEST2))
             IF         COND(&DEST3 *NE ' ') THEN(CHGVAR +
                          VAR(&ADRMAIL) VALUE(&ADRMAIL *BCAT &DEST3))
             IF         COND(&DEST4 *NE ' ') THEN(CHGVAR +
                          VAR(&ADRMAIL) VALUE(&ADRMAIL *BCAT &DEST4))
             IF         COND(&DEST5 *NE ' ') THEN(CHGVAR +
                          VAR(&ADRMAIL) VALUE(&ADRMAIL *BCAT &DEST5))
             IF         COND(&DEST6 *NE ' ') THEN(CHGVAR +
                          VAR(&ADRMAIL) VALUE(&ADRMAIL *BCAT &DEST6))
             IF         COND(&DEST7 *NE ' ') THEN(CHGVAR +
                          VAR(&ADRMAIL) VALUE(&ADRMAIL *BCAT &DEST7))
             IF         COND(&DEST8 *NE ' ') THEN(CHGVAR +
                          VAR(&ADRMAIL) VALUE(&ADRMAIL *BCAT &DEST8))
             IF         COND(&DEST9 *NE ' ') THEN(CHGVAR +
                          VAR(&ADRMAIL) VALUE(&ADRMAIL *BCAT &DEST9))
             IF         COND(&DEST10 *NE ' ') THEN(CHGVAR +
                          VAR(&ADRMAIL) VALUE(&ADRMAIL *BCAT &DEST10))
             DSPJOBLOG  OUTPUT(*PRINT)
             RTVJOBA    JOB(&JOB_NAME) USER(&USER) NBR(&JOB_NUM) +
                          TYPE(&JOBTYP)
             RTVNETA    SYSNAME(&SYSTEM)
             IF         COND(&JOBTYP *EQ '1') THEN(DO)
 FENETRE:    SNDRCVF
             IF         COND(&IN05) THEN(GOTO CMDLBL(MAIL))
             ELSE       CMD(GOTO CMDLBL(FENETRE))
             ENDDO
 MAIL:       CHKOBJ     OBJ(QTEMP/DUMP) OBJTYPE(*FILE)
             MONMSG     MSGID(CPF9801) EXEC(CRTPF FILE(QTEMP/DUMP) +
                           RCDLEN(132) SIZE(*NOMAX))
             CHKOBJ     OBJ(QTEMP/ERRORLST) OBJTYPE(*FILE)
             MONMSG     MSGID(CPF9801) EXEC(CRTPF FILE(QTEMP/ERRORLST) +
                          RCDLEN(132) SIZE(*NOMAX))
             CHKOBJ     OBJ(QTEMP/QPJOBLOG) OBJTYPE(*FILE)
             MONMSG     MSGID(CPF9801) EXEC(CRTPF FILE(QTEMP/QPJOBLOG) +
                          RCDLEN(132) SIZE(*NOMAX))
             CPYSPLF    FILE(ERRORLST) TOFILE(QTEMP/ERRORLST) +
                          JOB(&JOB_NUM/&USER/&JOB_NAME) SPLNBR(*LAST)
             CPYSPLF    FILE(QPPGMDMP) TOFILE(QTEMP/ERRORLST) +
                          JOB(&JOB_NUM/&USER/&JOB_NAME) +
                          SPLNBR(*LAST) MBROPT(*ADD)
             CPYSPLF    FILE(QPJOBLOG) TOFILE(QTEMP/ERRORLST) +
                          JOB(&JOB_NUM/&USER/&JOB_NAME) +
                          SPLNBR(*LAST) MBROPT(*ADD)
             CRTFLR     FLR(EMAIL)
             MONMSG     MSGID(CPF8A18)
             CPYTOPCD   FROMFILE(QTEMP/ERRORLST) TOFLR(EMAIL) +
                          TODOC(ERRORLST.TXT) REPLACE(*YES) +
                          TRNTBL(QTCPASC)
             CHGVAR     VAR(&OBJET) VALUE('Rapport détaillé de +
                          l''''erreur')
             CHGDOCD    DOC(ERRORLST.TXT) FLR(EMAIL) DOCD(&OBJET)
             CHGVAR     VAR(&MSG_ERR) VALUE('Cher service +
                          informatique, une erreur système a eu +
                          lieu sur le travail' *BCAT &JOB_NUM *TCAT +
                          '/' *TCAT &USER *TCAT '/' *TCAT &JOB_NAME +
                          *TCAT ', programme' *BCAT &PROGRAM *TCAT +
                          ', instruction' *BCAT &ERROR *TCAT ', +
                          vous trouverez ci-joint le DUMP le +
                          rapport détaillé de l''''erreur et la log')
             CHGVAR     VAR(&EMET) VALUE(&PROGRAM *TCAT '@' *TCAT +
                          &SYSTEM *TCAT '.fr')
             CHGVAR     VAR(&SUJET) VALUE('ERREUR système')
             CHGVAR     VAR(&CMD) VALUE('SNDDST TYPE(*DOC) +
                          TOINTNET(' *TCAT &ADRMAIL *TCAT ') DSTD(''' +
                          *TCAT &OBJET *TCAT ''') DOC(erreur.log) +
                          FLR(EMAIL) LONGMSG(''' *TCAT &MSG_ERR *tcat ''')')
             OVRPRTF    FILE(QPQUPRFIL) DEVTYPE(*AFPDS)
             CALL       PGM(QCMDEXC) PARM(&CMD &LNG)
             DLTF       FILE(QTEMP/ERRORLST)
             DLTDLO DLO(EMAIL)
FIN:         ENDPGM

Figure 7

MAILINFO

Les adresses méls uti­li­sées sont para­mé­trées dans la table MAILINFO. 

                R MAILINFOF
                  ID            10  0
                  REFERENCE     10
                  ADRMAIL       32
                                            UNIQUE
                R MAILINFOF                 PFILE(MAILINFO)
                K ID
                R MAILINFOF                 PFILE(MAILINFO)
                K REFERENCE

Figure 8

Petite pré­cau­tion, l’utilisateur qui génère l’erreur doit appar­te­nir aux pro­fils auto­ri­sés à envoyer des mails (WRKDIRE).

Un pro­gramme CLLE pour com­pi­ler tout ça peut s’avérer utile. Mettre la biblio­thèque où sera uti­li­sée cet outil en CURLIB. 

             PGM
/* Création de la fonction d'erreur non prévue */
             CRTPF      FILE(MAILINFO) SRCFILE(*CURLIB/QDDSSRC)
             MONMSG     MSGID(CPF0000)
             CRTLF      FILE(MAILINFOL1) SRCFILE(*CURLIB/QDDSSRC)
             MONMSG     MSGID(CPF0000)
             CRTLF      FILE(MAILINFOL2) SRCFILE(*CURLIB/QDDSSRC)
             MONMSG     MSGID(CPF0000)
             CRTPRTF    FILE(ERRORLST) SRCFILE(*CURLIB/QDDSSRC)
             CRTDSPF    FILE(FGESTERR) SRCFILE(*CURLIB/QDDSSRC)
             CRTRPGMOD  MODULE(QTEMP/GESTERR) +
                          SRCFILE(*CURLIB/QRPGLESRC) DBGVIEW(*ALL) +
                          OPTIMIZE(*FULL)
             CRTCLMOD   MODULE(QTEMP/MAILERR) +
                          SRCFILE(*CURLIB/QCLSRC) OPTIMIZE(*FULL) +
                          DBGVIEW(*ALL)
/* Création du programme de service          */
             CRTSRVPGM  SRVPGM(SERVICE) MODULE(QTEMP/GESTERR +
                          QTEMP/MAILERR) SRCFILE(*CURLIB/QSRVSRC)
 /* Création de la commande DSPFFDF            */
             CRTPF      FILE(QTEMP/TEST) RCDLEN(500)
             MONMSG     MSGID(CPF0000)
             DSPFFD     FILE(QTEMP/TEST) OUTPUT(*OUTFILE) +
                          OUTFILE(QTEMP/DSPFFDF)
             CRTCLMOD   MODULE(QTEMP/DSPFFDF) +
                          SRCFILE(*CURLIB/QCLSRC) OPTIMIZE(*FULL) +
                          DBGVIEW(*ALL)
             CRTPGM     PGM(DSPFFDF) MODULE(QTEMP/DSPFFDF) +
                          BNDDIR(*CURLIB/OUTILS)
             CRTCMD     CMD(DSPFFDF) PGM(*CURLIB/DSPFFDF)
             DSPFD      FILE(QTEMP/TEST) TYPE(*ACCPTH) +
                          OUTPUT(*OUTFILE) OUTFILE(QTEMP/DSPKEYF)
             CRTCLMOD   MODULE(QTEMP/DSPKEYF) +
                          SRCFILE(*CURLIB/QCLSRC) OPTIMIZE(*FULL) +
                          DBGVIEW(*ALL)
             CRTPGM     PGM(DSPKEYF) MODULE(QTEMP/DSPKEYF) +
                          BNDDIR(*CURLIB/OUTILS)
             CRTCMD     CMD(DSPKEYF) PGM(*CURLIB/DSPKEYF)
             DSPOBJD    OBJ(QTEMP/*ALL) OBJTYPE(*ALL) +
                          OUTPUT(*OUTFILE) OUTFILE(QTEMP/DSPOBJDL)
             CRTCLMOD   MODULE(QTEMP/CHGOWNOBJL) +
                          SRCFILE(*CURLIB/QCLSRC) OPTIMIZE(*FULL) +
                          DBGVIEW(*ALL)
             CRTPGM     PGM(CHGOWNOBJL) MODULE(QTEMP/CHGOWNOBJL) +
                          BNDDIR(*CURLIB/OUTILS)
             CRTCMD     CMD(CHGOWNOBJL) PGM(*CURLIB/CHGOWNOBJL)
             DSPOBJD    OBJ(*CURLIB/*ALL) OBJTYPE(*QMQRY) OUTPUT(*OUTFILE) +
                          OUTFILE(QTEMP/DSPQMQRYD)
             CRTCLMOD   MODULE(QTEMP/RTVQMLIB) SRCFILE(*CURLIB/QCLSRC) OPTIMIZE(*FULL) +
                          DBGVIEW(*ALL)
             CRTPGM     PGM(RTVQMLIB) MODULE(QTEMP/RTVQMLIB) BNDDIR(*CURLIB/OUTILS)
             CRTCMD     CMD(RTVQMLIB) PGM(*CURLIB/RTVQMLIB)
             ENDPGM

Figure 9