"MIDRANGE-L" <midrange-l-bounces@xxxxxxxxxxxx> wrote on 06/19/2017 
06:10:48 PM:
I didn't miss the point. Thanks to Brian for sharing it.
The reason I don't consider this a "correction" to what you were
saying is that, for my purposes, it's just too far down the rabbit
hole and off the beaten path.
        Understood.  If you're interested, I have a service procedure that 
can be called from CLLE to retrieve up to the last 10 messages from the 
current joblog.  It is not fully encapsulated, though, so where it calls 
other service routines you would have to supply your own code to obtain an 
encapsulated version of this.  It also utilizes definitions from 
IBM-supplied RPG copybooks in the QSYSINC library.
        It returns message type, message id, message file, msgfile 
library, and message replacement data for each of those up to 10 messages 
in an array that can be looped through in CLLE to make it easy to examine 
DIAG messages in reverse order.  I currently use it as part of my standard 
batch error handling routine which sends a diagnostic email expanding the 
failing message and attaching the last 10 joblog messages for ease of 
diagnosis -- potentially avoiding having to either examine printed joblogs 
or try and reproduce the error in interactive debug.
        This is the service procedure part:
// data structure to return message information
dcl-ds GenUtl_MsgInfo        dim(20) qualified;
  Id                         char(7);
  Type                       char(10);
  File                       char(10);
  FLib                       char(10);
  Data                       varchar(3000);
end-ds;
//========================================================================
// get information about the last nnnnn messages in the current joblog
//========================================================================
dcl-proc GenUtl_GetLastJoblogMessages export;
  dcl-pi *n;
    pMsgCnt                  packed(5:0);
    pMsgInfo                 likeds(GenUtl_MsgInfo)
                             dim(%elem(GenUtl_MsgInfo))
                             options(*varsize);
  end-pi;
  dcl-s iMsgCnt              like(pMsgCnt);
  dcl-s curmsg               like(pMsgCnt);
  dcl-s idx                  like(pMsgCnt);
  dcl-s ofs                  int(10:0);
  dcl-s ofs2                 like(ofs);
  dcl-s msgtyp               char(10);
  dcl-s ListRcvr             char(32767);
  dcl-ds selinfo             qualified;
    MSI                      likeds(QGYOMSI);
    QGYFID                   int(10:0) dim(1);
    QGYCMQN                  char(10);
  end-ds;
  iMsgCnt = pMsgCnt;              // number of messages requested
  if iMsgCnt < 1;                 // if last *EXCP message requested
    iMsgCnt = 1;                  // default to 1 message
  endif;
  clear selinfo;                  // clear selection information ds
  selinfo.MSI.QGYLD = '*PRV';     // get most recent messages first
  selinfo.MSI.QGYJN = '*';        // from this job's joblog
  selinfo.MSI.QGYSMK = *hival;    // starting at end of joblog
  selinfo.MSI.QGYIDO = %len(selinfo.MSI); // offset to selection criteria
  selinfo.MSI.QGYNBRF00 = 1;      // number of field id's
  selinfo.MSI.QGYQO = selinfo.MSI.QGYIDO
                    + %size(selinfo.QGYFID:*ALL); // offset to msg que 
name
  selinfo.MSI.QGYMQNS = %len(selinfo.QGYCMQN); // length of msg queue name
  selinfo.QGYFID(1) = 0201;       // replacement data or impromptu msg 
text
  selinfo.QGYCMQN = '*';          // call stack message queue name
  callp IBMAPI_ListJobLogMessages( ListRcvr: %len(ListRcvr): QGYOLI
                                 : 1: selinfo: %len(selinfo): ApiErrC);
  if ApiErrC.BytAvail > *zero;    // if API error, report it
    callp GenUtl_Escape(ApiErrC.MsgId: ApiErrC.MsgData: 'QCPFMSG');
  endif;
  curmsg = 1;                     // set message counter
  idx = *zero;                    // set message index
  dow idx < iMsgCnt               // load requested number of messages
  and ApiErrC.MsgId <> 'GUI0006'; // unless end of message list exceeded
    QGYORV = %subst(ListRcvr: 1: %len(QGYORV)); // map message header
    ofs = QGYOTFR + 1;            // set offset to field identifier (FID)
    QGYOIDFI = %subst(ListRcvr: ofs: %len(QGYOIDFI)); // map FID header
    ofs2 = ofs + %len(QGYOIDFI);  // set offset to data associated w/ FID
    select;                       // interpret message type
      when QGYMT = '01';          // completion
        msgtyp = '*COMP';
      when QGYMT = '02';          // diagnostic
        msgtyp = '*DIAG';
      when QGYMT = '04';          // informational
        msgtyp = '*INFO';
      when QGYMT = '05';          // inquiry
        msgtyp = '*INQ';
      when QGYMT = '06';          // sender's copy
        msgtyp = '*COPY';
      when QGYMT = '08';          // request
        msgtyp = '*RQS';
      when QGYMT = '10';          // request with prompting
        msgtyp = '*RQS';
      when QGYMT = '14';          // notify, exception already handled
        msgtyp = '*NOTIFY';
      when QGYMT = '15';          // escape, exception already handled
        msgtyp = '*ESCAPE';
      when QGYMT = '16';          // notify, exception not yet handled
        msgtyp = '*NOTIFY';
      when QGYMT = '17';          // escape, exception not yet handled
        msgtyp = '*ESCAPE';
      other;                      // unknown
        msgtyp = '*MT' + QGYMT;
    endsl;
    if pMsgCnt > *zero            // if all msg types requested
    or pMsgCnt = *zero            // or only exception messages
    and msgtyp = '*ESCAPE';       // and this is an exception msg
      idx += 1;                   // then increment message index
      pMsgInfo(idx).Id = QGYMID;  // and load message id
      pMsgInfo(idx).Type = msgtyp; // message type
      pMsgInfo(idx).File = QGYMFILN; // message file name
      pMsgInfo(idx).FLib = QGYML; // message file library name
      pMsgInfo(idx).Data = %trimr(%subst(ListRcvr: ofs2: QGYDL)); // repl. 
data
    endif;
    if idx < iMsgCnt;             // max requested not exceeded?
      curmsg += 1;                // increment message counter
      callp IBMAPI_GetListEntry( ListRcvr: %len(ListRcvr): QGYRH00
                               : QGYOLI: 1: curmsg: ApiErrC); // get prev. 
msg
      if ApiErrC.BytAvail > *zero // if API error, report it
      and ApiErrC.MsgId <> 'GUI0006'; // unless it is end of list
        callp GenUtl_Escape(ApiErrC.MsgId: ApiErrC.MsgData: 'QCPFMSG');
      endif;
    endif;
  enddo;                          // loop on message count
  callp IBMAPI_CloseList(QGYRH00: ApiErrC); // close the list
  if ApiErrC.BytAvail > *zero;    // if API error, report it
    callp GenUtl_Escape(ApiErrC.MsgId: ApiErrC.MsgData: 'QCPFMSG');
  endif;
  pMsgCnt = idx;                  // pass back number of messages 
retrieved
  return;                         // return to caller
end-proc;
        ...and to call from CL:
/******************************************************************************/
/* Data Structure for JobLog Message Info (See GenUtl_MsgInfo in UT010SV)  
  */
/*----------------------------------------------------------------------------*/
/* &MSG_INFID  is the message id from the message file indicated below;  
*/
/* &MSG_INFTPE is the type (*DIAG, *ESCAPE, etc.) for the indicated 
message;  */
/* &MSG_INFFLE is the message file for the indicated message id;    */
/* &MSG_INFFLB is the library for the indicated message file;    */
/* &MSG_INFDLN is the length of the following substitution data; and,  */
/* &MSG_INFDTA is the substitution data for the indicated message id.  */
/******************************************************************************/
  DCL VAR(&MSGINFO) TYPE(*CHAR) LEN(30390) /* array with 10 elements */
  DCL VAR(&MSGINFP) TYPE(*PTR)  ADDRESS(&MSGINFO)
  DCL VAR(&MSGINFE) TYPE(*CHAR) STG(*BASED) LEN(3039) BASPTR(&MSGINFP)
    DCL VAR(&MSG_INFID)  TYPE(*CHAR) LEN(7)  STG(*DEFINED) DEFVAR(&MSGINFE 
1)
    DCL VAR(&MSG_INFTPE) TYPE(*CHAR) LEN(10) STG(*DEFINED) DEFVAR(&MSGINFE 
8)
    DCL VAR(&MSG_INFFLE) TYPE(*CHAR) LEN(10) STG(*DEFINED) DEFVAR(&MSGINFE 
18)
    DCL VAR(&MSG_INFFLB) TYPE(*CHAR) LEN(10) STG(*DEFINED) DEFVAR(&MSGINFE 
28)
    DCL VAR(&MSG_INFDLN) TYPE(*UINT) LEN(2)  STG(*DEFINED) DEFVAR(&MSGINFE 
38)
    DCL VAR(&MSG_INFDTA) TYPE(*CHAR) LEN(3000) STG(*DEFINED) 
DEFVAR(&MSGINFE 40)
             DCL        VAR(&SQ)       TYPE(*DEC)  LEN(2 0)
             DCL        VAR(&MSGIDX)   TYPE(*INT)  LEN(2)
             DCL        VAR(&MSGMAX)   TYPE(*INT)  LEN(2)
    /* ============================================================= */
    /* =============   R E T R I E V E   J O B L O G   ============= */
    /* ============================================================= */
             CHGVAR     VAR(&MSGCNT) VALUE(10)
             CALLPRC    PRC(GENUTL_GETLASTJOBLOGMESSAGES) +
                          PARM((&MSGCNT) (&MSGINFO))
    /* loop through joblog and append to email text */
             CHGVAR     VAR(&TXTBODY) VALUE(&TXTBODY *TCAT +
                          '<br><br><br>Joblog messages :')
             CHGVAR     VAR(&MSGMAX) VALUE(&MSGCNT)
             DOFOR      VAR(&MSGIDX) FROM(1) TO(&MSGMAX) BY(+1)
                IF         COND(&MSG_INFID *GT ' ') THEN(DO)
                   IF         COND(&MSG_INFDLN *LT 1) THEN(DO)
                      CHGVAR     VAR(&MSG_INFDLN) VALUE(1)
                   ENDDO
                   CHGVAR     VAR(&ERRMDATA) VALUE(%SST(&MSG_INFDTA +
                                1 &MSG_INFDLN))
                   CALL       PGM(UTMMERGR) PARM(&MSG_INFID &MSG_INFFLE +
                                &MSG_INFFLB &ERRMDATA &ERRMTEXT &DTALEN)
                   SELECT
                      WHEN       COND(&DTALEN *LT 1) THEN(DO)
                         CHGVAR     VAR(&DTALEN) VALUE(1)
                      ENDDO
                      WHEN       COND(&DTALEN *GT 90) THEN(DO)
                         CHGVAR     VAR(&DTALEN) VALUE(90)
                      ENDDO
                   ENDSELECT
                   CHGVAR     VAR(&TXTBODY) VALUE(&TXTBODY *TCAT +
                                '<br>' *CAT '-' *CAT %CHAR(&SQ) +
                                *BCAT %SST(&MSG_INFTPE 1 5) +
                                *CAT ' ' *CAT &MSG_INFID *CAT ' ' +
                                *CAT %SST(&ERRMTEXT 1 &DTALEN))
                ENDDO
                CHGVAR     VAR(&SQ) VALUE(&SQ + 1)
                CHGVAR     VAR(%OFS(&MSGINFP)) VALUE(%OFS(&MSGINFP) +
                             + %LEN(&MSGINFE))
             ENDDO
Sincerely,
Dave Clark
As an Amazon Associate we earn from qualifying purchases.