)MSG CI@* /**********************************************************************/ /* */ /* */ /* */ /* Related - SYSP.PRO.X00.CA.OPS.REXX.U(TXT2SYSP) */ /* Added required destinations with DLs. */ /* Globals - GLVTEMP1.CI@_____.wtoid */ /* Notes - The default logic of this rule will suppress and */ /* from the Syslog specific CI@* MLWTO messages & */ /* re-issue the MLWTO with desired characteristics */ /* as per severity in MLWTO. The Single-Line WTO */ /* (SLWTO) will have characteristics adjusted */ /* and be allowed to display with the modified */ /* characteristics since the actual SLWTO will */ /* be updated during this rule's processing. */ /* */ /* MLWTO messages are processed one line at a time */ /* within an AOF rule. First the primary line is */ /* processed by the rule, and then each subsequent */ /* data line. If a MLWTO is to be suppressed based */ /* on the value of some string within a data line of */ /* the MLWTO (suppress only if line 3 contains 'ABCD') */ /* then the AOF rule must SUPPRESS (or DELETE) upon */ /* the processing of the primary line. Therefore, the */ /* logic of the rule must store all the lines of the */ /* MLWTO in a unique variable, and then upon the */ /* processing of the end-line of the message,determine */ /* if the suppressed message should be re-issued. This */ /* sample rule demonstrates this logic. While specific */ /* for the sample DB2 message, the same rule logic */ /* would apply for any MLWTO. */ /* The logic of this sample was created from the */ /* MLWTO sample rule located within the */ /* OPSMVShlq.CCLXRULES dataset. Refer to this */ /* member for complete details on how OPS/MVS */ /* processes MLWTO messages and the logic that can */ /* be used to process them. */ /* This rule demonstrates: */ /* 1) Logic needed to process MLWTO messages */ /* specifically if the desired logic is to */ /* suppress a MLWTO based on some data found */ /* within a data line of the MLWTO. */ /* 2) Creating asid uniqueness via the use of */ /* OPS/MVS GLVTEMP1 variables. */ /* 3) Using the Address WTO host environment to */ /* issue MLWTO messages. */ /* 3) Utilizing the OPSVALUE() to interrogate */ /* global variables. */ /* */ /* Steps needed for implementation. */ /* 1) Review and customize any needed logic to */ /* accomplish the desired automation specifically */ /* the suppress_codes variable with the list of */ /* codes that determine if this MLWTO should be */ /* suppressed. */ /* 2) Enable/auto-enable the rule within a */ /* production OPS/MVS ruleset. */ /* */ /* Rule Name: CI@ */ /* Rule Type: Message */ /* Rule Function: notify operators & FutureCore R3 of CICS */ /* transaction abends */ /* Author: sys1kss */ /* History: 2024.01.23 */ /* 20240130 kss Non-Processing of redundant SLWTOs in a given */ /* interval implemented. */ /* 20240125 kss Additional requests incorporated */ /* 20240124 kss Additional requests incorporated */ /* 20240123 kss Original version from MQ@ */ /* */ /* Message is generated by AMI Ops for CICS. */ /* */ /* e.g. */ /* CI@DUMP SEV=MIN CICSADM4 DumpCode: SR0001 (CurrDumps >= 3) CALL BART */ /* ONCALL AD2T DB2 STATUS CALL FAILURE, SR0001 CEE3207S DATA EXCEPTION */ /* CODE=0C7 TBBRMPT COMP UNITDE=OC7 TBBRMPT COMP UNIT */ /* */ /*--+----1----+----2----+----3----+----4----+----5----+----6----+----7*/ /* CI@TB/EVF TBQ2 LOG RECORD NOT WRITTEN FOR UUID CALL TB/EVF ON CALL */ /* */ /* CI@TR24 TOCT IPPCZ533 ERROR WRITING EVENT FILE CALL TR24ON CALL */ /* */ /* *** This message will be ignored. *** */ /* */ /* CI@DUMP SEV=MIN Alarm definition CI@DUMP in group DEFAULT has been */ /* uninstalled */ /* */ /*--------------------------------------------------------------------*/ )Init /*--------------------------------------------------------------------*/ /* This code will fire ONCE when the rule is enabled */ /*--+----1----+----2----+----3----+----4----+----5----+----6----+----7*/ true = 1; false = 0; cnt_msgs = 0 msg_idx = 'CI@*' debug_ = true; /* DO debug processing-RUN DEBUGGING! */ debug_ = false; /* DO NOT do debug processing-RUN NORMALLY! */ lpar_name = Right(OPSINFO("SYSNAME"),4) sysclone1 = Substr(OPSINFO("SYSCLONE"),1,1) /* Env: P,A,Q,D,T,H */ /* Only enable in PRD1 & QAD1. */ If POS(sysclone1,'P Q') > 0 then Return "ACCEPT"; /* ENABLE on all Production & QA LPARs. */ Else Return "REJECT"; /* DISABLE on all non-prod/QA LPARs. */ Options 'NOFIRELIMIT NOMAXTIME' /* Disable global AOF limits */ maxcnt_SLWTO = 1 /* Modify to max count (x times..) */ /* Skip MLWTO for now. Probably need MLWTO )MSG spec rule maxcnt_MLWTO = ? depends on MLWTO /* Modify to max count (x times..) */ */ maxtime = 1800 /* Modify to max time (in y seconds) */ )Proc /* This code will fire each time AOF detects an CI@* */ /* message event on the system. */ If debug_ then trace ir; /*--------------------------------------------------------------------*/ /* If msg.token = 'XAOF' then this is a reissued MLWTO from this */ /* rule, so do not process. This technique is needed to avoid a */ /* loop within this rule. */ /*--+----1----+----2----+----3----+----4----+----5----+----6----+----7*/ if msg.token = 'XAOF' then Return cnt_msgs = cnt_msgs + 1 /*--------------------------------------------------------------------*/ /* Obtain the WTOID and convert to viewable decimal format. */ /*--+----1----+----2----+----3----+----4----+----5----+----6----+----7*/ wtoid = C2D(msg.wtoid) /*--------------------------------------------------------------------*/ /* Obtain the message id. This will be used as part of the variable */ /* name that gets created to hold each data line of this MLWTO msg. */ /*--+----1----+----2----+----3----+----4----+----5----+----6----+----7*/ msgid = msg.id /*--------------------------------------------------------------------*/ /* OPSTHRSH action suppression */ /*--+----1----+----2----+----3----+----4----+----5----+----6----+----7*/ if msg.singleln = '1' then /* SLWTO */ Do; maxtime = 1800 /* Modify to max time (in y seconds) */ Parse Var MSG.TEXT 'CI@' msg_type . Select; When msg_type = 'TB/EVF' then Do; compare_arg = Substr(MSG.TEXT,4,40) /* msg_type for len 40 */ thresh_cnt = OPSTHRSH('C',maxtime,compare_arg,'4') if thresh_cnt \= maxcnt_SLWTO then Return 'NORMAL' End; When msg_type = 'TR24' then Do; compare_arg = Substr(MSG.TEXT,4,45) /* msg_type for len 45 */ thresh_cnt = OPSTHRSH('C',maxtime,compare_arg,'4') if thresh_cnt \= maxcnt_SLWTO then Return 'NORMAL' End; Otherwise Nop; End; End; /* If MLWTO then do GLV stuff */ if msg.multiln = '1' then Do; /*--------------------------------------------------------------------*/ /* Define stem name of variables that will hold each line of this */ /* specific MLWTO using the wtoid and msgid in the name to create */ /* uniqueness between each occurrence of this MLWTO. Primary and data */ /* lines of an MLWTO have the same internal wtoid. */ /*--+----1----+----2----+----3----+----4----+----5----+----6----+----7*/ varstemname = 'GLVTEMP1.'msgid'.'wtoid /*--------------------------------------------------------------------*/ /* See how many variables with this WTOID exist and add 1 to it so */ /* we can create a new variable for this line of the message. We'll */ /* use the 'K' option of the OPS/REXX OPSVALUE() to obtain the */ /* current count. A zero will be returned if this is the primary line */ /* (first line of message) being processed. */ /*--+----1----+----2----+----3----+----4----+----5----+----6----+----7*/ savedlines = OPSVALUE(varstemname,'K') varcntr = savedlines + 1 /*--------------------------------------------------------------------*/ /* Create actual name of variable that will hold this line. The cntr */ /* will be appended to the variable stem name. */ /*--+----1----+----2----+----3----+----4----+----5----+----6----+----7*/ varname = varstemname||'.'||varcntr /*--------------------------------------------------------------------*/ /* Set the variable that was created to value of this message using */ /* the 'U' option of the OPSVALUE(). */ /*--+----1----+----2----+----3----+----4----+----5----+----6----+----7*/ varvalue = msg.text setvar = OPSVALUE(varname,'U',varvalue) End; /* Do */ /*--------------------------------------------------------------------*/ /* Check the flag to indicate that the end line is being processed */ /* or if this is a single-line WTO. If so, then re-issue the WTO */ /* with the appropriate attributes. */ /*--+----1----+----2----+----3----+----4----+----5----+----6----+----7*/ if (msg.endln = '1' | msg.singleln = '1') then do /*------------------------------------------------------------------*/ /* Invoke sub-routine to reissue the MLWTO or single-line WTO. */ /*+----1----+----2----+----3----+----4----+----5----+----6----+----7*/ call reissue_msg /*------------------------------------------------------------------*/ /* Delete the variables. */ /*+----1----+----2----+----3----+----4----+----5----+----6----+----7*/ if msg.endln = '1' then delvars = OPSVALUE(varstemname,'R') end else return 'SUPPRESS' exit /*--------------------------------------------------------------------*/ /*------------------------- Sub Routines -----------------------------*/ /*--------------------------------------------------------------------*/ reissue_msg: /*--------------------------------------------------------------------*/ /* Obtain the variables set from the rule that contain each message. */ /* Variables getvar.# will contain the value of each line. Use these */ /* stemmed variables within the TEXTVAR of the Address WTO. */ /*--+----1----+----2----+----3----+----4----+----5----+----6----+----7*/ /* Only for MLWTO. If single line WTO skip GLV stuff. */ If msg.multiln = '1' then Do; text_2u = '' getvars = OPSVALUE(varstemname,'K') do v = 1 to getvars varname = varstemname||'.'||v getvar.v = OPSVALUE(varname,'O') text_2u = text_2u getvar.v /* may need to use || if spaces in */ end End; /* Do */ /* Parse out msg type for both MLWTO & SLWTO. */ Select; When msg.multiln = '1' then Do; Parse Var getvar.1 'CI@' msg_type . If msg_type = 'DUMP' then Do; Parse Upper Var getvar.1 'CI@' 'SEV=' severity . 'DUMPCODE: ', abend_code . /* If not one of these abends, we are not interested. */ If POS(abend_code,'AD2T SR0001') = 0 then Signal reissue_msg_return; End; /* Do */ End; /* Do */ When msg.singleln = '1' then Do; Parse Var MSG.TEXT 'CI@' msg_type . If msg_type = 'DUMP' then Do; Parse Upper Var MSG.TEXT 'CI@' 'SEV=' severity . 'DUMPCODE: ', abend_code . /* If not one of these abends, we are not interested. */ If POS(abend_code,'AD2T SR0001') = 0 then Signal reissue_msg_return; End; /* Do */ End; /* Do */ Otherwise Nop /* Should never happen. */ End; /* Select */ If msg.singleln = '1' then /* SLWTO */ Do; MSG.DESC = OPSBITS("JOBSTAT ") End; /* Do */ If msg.multiln = '1' then /* MLWTO */ Do; desccode = '6' routecde = 2 /* Set MSTRINFO as default */ End; /* Do */ /* Don't need SEV= for DUMP--take all AD2T & SR0001 abends If (((POS(severity,'MIN CRI') > 0) & (msg_type = 'DUMP')) |, (POS(msg_type,'DUMP') = 0)) then */ Do; /*---------------------------------------------------------*/ /* Change WTO descriptor code - highlight & hold (critical */ /* event action) */ /* OPSBITS(CRITEVET) or (11). */ /*---------------------------------------------------------*/ If msg.singleln = '1' then /*single line WTO */ Do; MSG.DESC = OPSBITS(11) End; /* Do */ If msg.multiln = '1' then /*MLWTO */ Do; routecde = 1 /* MSTRACTN */ desccode = '11' End; /* Do */ End; /* Do */ /*------------------------------------------------------------*/ /* Send text msgs! */ /*------------------------------------------------------------*/ If POS(sysclone1,'P Q') > 0 then Do; txt_msg_id = '$$TEST$$' /* invoke debug display */ txt_msg_id = 'CICS_err:' If msg.multiln = '1' then /*MLWTO */ Nop; /* already loaded 'text_2u' */ If msg.singleln = '1' then text_2u = MSG.TEXT /*--------------------------------------------------------------------*/ /* Check length of lines and concat to max then do again, if more */ /* until all sent. */ /*--------------------------------------------------------------------*/ address TSO /* cmd + parm <= 256 bytes */ /* Use longest group name that will be used as 'dest'. */ If Length("TXT2SYSP " lpar_name " DAAS_DF_PROD " txt_msg_id text_2u), >= 250 then Do; Say 'Alert is too long! Change process to handle this! ', 'Length is ', Length("TXT2SYSP " lpar_name " DAAS_DF_PROD " txt_msg_id text_2u), ' Msg lost!' text_2long = Substr(text_2u,1,250) "TXT2SYSP " lpar_name " GROUP " txt_msg_id text_2long "TXT2SYSP " lpar_name " GROUP " txt_msg_id " Msg not sent. ", "Investigate." "TXT2SYSP " lpar_name " ME " txt_msg_id text_2long "TXT2SYSP " lpar_name " ME " txt_msg_id " Msg not sent. ", "Investigate." End; /* Do */ /* */ /* z Systems; DEPOSIT Team; FC_PRD / FC_QAD (BaNCS) Support */ /* etc. */ /* */ Select; When POS(sysclone1,'P') then Do; Select; When msg_type = 'TB/EVF' then Do; "TXT2SYSP " lpar_name " DEPOSIT " txt_msg_id text_2u "TXT2SYSP " lpar_name " BNK_CRD_PRG " txt_msg_id text_2u "TXT2SYSP " lpar_name " MF_DEV_MGRS " txt_msg_id text_2u End; /* Do */ When (msg_type = 'TRANS24' | msg_type = 'TR24') then Do; "TXT2SYSP " lpar_name " FC_PRD " txt_msg_id text_2u "TXT2SYSP " lpar_name " GROUP " txt_msg_id text_2u "TXT2SYSP " lpar_name " MF_DEV_MGRS " txt_msg_id text_2u "TXT2SYSP " lpar_name " BNK_CRD_PRG " txt_msg_id text_2u End; /* Do */ When msg_type = 'DUMP' then Do; "TXT2SYSP " lpar_name " BNK_CRD_PRG " txt_msg_id text_2u "TXT2SYSP " lpar_name " MF_DEV_MGRS " txt_msg_id text_2u "TXT2SYSP " lpar_name " DEPOSIT " txt_msg_id text_2u End; /* Do */ When msg_type = 'RCON' then /* probably none of these */ Do; "TXT2SYSP " lpar_name " FC_PRD " txt_msg_id text_2u "TXT2SYSP " lpar_name " GROUP " txt_msg_id text_2u "TXT2SYSP " lpar_name " DEPOSIT " txt_msg_id text_2u "TXT2SYSP " lpar_name " MF_DEV_MGRS " txt_msg_id text_2u End; /* Do */ When msg_type = 'TIB' then /* probably none of these */ Do; "TXT2SYSP " lpar_name " FC_PRD " txt_msg_id text_2u "TXT2SYSP " lpar_name " GROUP " txt_msg_id text_2u "TXT2SYSP " lpar_name " DEPOSIT " txt_msg_id text_2u "TXT2SYSP " lpar_name " MF_DEV_MGRS " txt_msg_id text_2u End; /* Do */ When msg_type = 'BART' then /* probably none of these */ Do; "TXT2SYSP " lpar_name " FC_PRD " txt_msg_id text_2u "TXT2SYSP " lpar_name " GROUP " txt_msg_id text_2u "TXT2SYSP " lpar_name " DEPOSIT " txt_msg_id text_2u "TXT2SYSP " lpar_name " MF_DEV_MGRS " txt_msg_id text_2u End; /* Do */ Otherwise Do; no_app = 'This application, 'msg_type ||', has not been ', 'requested to be set up. Please make the request.', ' Thank you.' "TXT2SYSP " lpar_name " FC_PRD " txt_msg_id no_app "TXT2SYSP " lpar_name " GROUP " txt_msg_id no_app End; /* Do */ End; /* Select */ End; /* Do */ When POS(sysclone1,'Q') then Do; "TXT2SYSP " lpar_name " FC_QAD " txt_msg_id text_2u End; /* Do */ Otherwise; Nop; End; /* Select */ If debug_ then "TXT2SYSP " lpar_name " ME " txt_msg_id text_2u End; /* Do */ /*-------------------------------------------------------------------*/ /* Reissue MLWTO using Address WTO and TEXTVAR keyword with obtained */ /* stemmed variables. Set TOKEN of 'XAOF' so the check at the */ /* beginning of this rule will determine that this MLWTO should not */ /* be reprocessed. */ /*-+----1----+----2----+----3----+----4----+----5----+----6----+----7*/ /* Do same thing for single line WTO--processing the actual WTO */ /* What about token so don't repeat SLWTO? */ /* Not re-issuing the SLWTO so don't need token. */ /* SLWTO: only modify the WTO characteristics, send text/email */ /* then just let the SLWTO flow: return 'NORMAL' */ Select; When msg.multiln = '1' then /*MLWTO */ Do; If debug_ then Do; Say 'C2X(msg.route): ' C2X(msg.route) Say 'msg.route: ' msg.route Say 'OPSBN(msg.route): ' OPSBN(msg.route) Say 'DESC: OPSBN(desccode) desccode: ' OPSBN(desccode) ' ' desccode Say 'ROUTE: OPSBN(routecde) routecode: ' OPSBN(routecde), ' ' routecde End; /* Do */ Parse Var getvar.1 msgid text_sans_msgid /* Do this to eliminate 2nd copy of msgid in line 1 & otherwise */ /* MLWTO line 1 would be too long */ getvar.1 = text_sans_msgid address WTO "Msgid("msg.id") Textvar(getvar.) ", "Token(XAOF) Desc("desccode") Route("routecde") " /* get & print explanation for WTO RC */ If rc <> 0 then Do; Pull stuff; Say 'MLWTO error: ' stuff End; /* Do */ End; /* Do */ When msg.singleln = '1' then Nop; /* return 'NORMAL' will update SLWTO */ Otherwise Nop /* Should never happen. */ End; /* Select */ reissue_msg_return: return /* from this routine back to the stmt after the 'CALL' */ /*--------------------------------------------------------------------*/ /* The termination section will notify the console & Systems Tech */ /* oncall if the rule is disabled. */ /* If this is executed due to CA OPS/MVS shutdown, */ /* it will WTO (non-held/lowlite) & send a message to the OPSLOG */ /* with the value of the static variable cnt_msgs, which */ /* was calculated during the )PROC section of the rule. */ /*--------------------------------------------------------------------*/ )TERM /* This code will fire ONCE when the rule is disabled or if */ /* OPS is shutting down. */ /* */ CONSOLE = OPSINFO('MSTCONSNM') If CONSOLE = '' then CONSOLE = OPSINFO('LOCMSTCONSNM') If OPSINFO('PRODUCTSTATUS') = 'TERM' then /* If OPS/MVS shutting down */ Do; /*---------------------------------------------------------*/ /* Send WTO to console - normal intensity & scrollable. */ /*---------------------------------------------------------*/ msg_id = 'INFO:' text_2u = "Total '"msg_idx"' messages "||, " = "cnt_msgs Address WTO "MSGID("||msg_id||") TEXT('" text_2u " ')", " LOWLITE CNNAME("CONSOLE")" LOGTOTALS = OPSSEND('*','B',text_2u) /* Put in OPSLOG, too. */ End; Else /* If DISABLE of this rule. */ Do; /*---------------------------------------------------------*/ /* Send WTO to console - highlight & hold */ /*---------------------------------------------------------*/ msg_id = 'INFO:' text_2u = "Total '"msg_idx"' messages "||, " = "cnt_msgs Address WTO "MSGID("||msg_id||") TEXT('" text_2u " ')", " HILITE CNNAME("CONSOLE")" rule_name = OPSINFO('PROGRAM') /* ruleset.rule name */ msg_id = 'Notify:' text_2u = 'Rule: ' rule_name ' DISABLED--CI@*'||, ' BaNCS problem notification no longer available!' text_2u = text_2u 'Notify Mainframe Systems immediately!' /*---------------------------------------------------------*/ /* WTO may be too long--verify & adjust, if needed! */ /*---------------------------------------------------------*/ Address WTO "MSGID("||msg_id||") TEXT('" text_2u " ')", " HILITE CNNAME("CONSOLE")" /*---------------------------------------------------------*/ /* Send text msg to Systems On-Call */ /*---------------------------------------------------------*/ txt_msg_id = 'URGENT:' address TSO /* cmd + parm <= 256 bytes */ If debug_ then "TXT2SYSP " lpar_name " ME " txt_msg_id text_2u Else "TXT2SYSP " lpar_name " ONCALL " txt_msg_id text_2u /*---------------------------------------------------------*/ LOGTOTALS = OPSSEND('*','B',text_2u) /* Put in OPSLOG, too. */ End; Return 'NORMAL';