适宜读者:(一年及以上主机经验)
背景知识:(z/OS基础知识,REXX语法,SDSF基础知识)
摘要:本文主要介绍如何利用REXX在z/OS系统日志中实时提取所有指定关键字行。
0. 概述:
主机用户大多业务量庞大,数据分析必不可少,很多情况下,需要对系统的全部日志数据进行实时提取及分析,但系统日志的更新速度较快,如果不采取适当的方法则只能提取到系统最后生成的部分日志。因此,本文开发了REXX脚本来扫描全部系统日志,并将其中匹配的内容全部写入数据集。
1. 背景问题及解决方案
主机维护人员需要经常查看系统日志来确认系统的运行状态。这一操作主要由维护人员手工进行,费时费力,并且由于系统日志更新很快,人工维护难免漏掉一些重要信息,因此,需要一个实时监控及提取重要信息的自动化工具。
z/OS中有OPERLOG和SYSLOG这两类系统日志,OPERLOG一般用于SYSPLEX,而SYSLOG用于MONOPLEX。可以用"DISPLAY CONSOLES,HARDCOPY"命令来查看当前系统支持那种系统日志。如果返回的消息为"LOG=(SYSLOG|OPERLOG)",则说明当前系统支持两种系统日志;如果返回的消息为"LOG=(SYSLOG)",则说明当前系统仅支持SYSLOG,当然这时要想使用OPERLOG,需要先对其进行安装。本文以SYSLOG为例来进行示例,OPERLOG的用法可以以此类推。
在REXX中,可以利用 Address SDSF "ISFLOG READ TYPE(SYSLOG)" 语句来读取系统日志,并将所读取内容存入STEM变量“isfline.”中,用户可以利用isfline.来获取日志内容。然而,本语句读取的只是脚本执行时系统中现有的日志。脚本运行结束后,系统后续的日志将无从获取。
这里,大家很容易想到采用循环来解决这一问题,不过紧接着问题就出现了,因为第一次循环结束时的syslog信息往往会出现在第二次循环的开始区间;或者当系统日志暂时或长时间不再更新时,脚本会一直重复提取最后留存日志中的相关信息,这样久而久之,将会出现大量的信息重复,占用大量的磁盘空间,并为后续的信息提取及分析带来很大的干扰。
因此,本文主要利用系统日志每次循环的最后日志行来避免日志信息的重复提取,从而实现实时且不重复读取全部系统日志的目的。系统日志的提取流程如下。

图1 系统日志提取流程
2. 系统日志实时提取示例
首先,需要分配一个源PS数据集用来存储关键字及其他相关参数。这里的“其他相关参数”用来指定需提取关键字行上下所需提取的日志行的数量。在此源PS数据集中,可以写入需提取的所有关键字信息,不过,每行只能存放一组关键字,最后一行用来指定相关参数,并且需用一分隔符来进行区分。所用分隔符切勿与系统日志内容重复。在本文中,选用<!---!>作为分隔符。例如,PS源数据集中的记录格式如下。
*************************** Top of Data **************************
000001 IBM POWER SYSTEM!
000002 YOURID
000003 <!---!> 1 1
************************* Bottom of Data *************************
其中,“IBM POWER SYSTEM!”为所需提取的第一组关键字,“YOURID”为第二组关键字,<!---!>为分隔符,后边的两个参数,分别表示需同时提取关键字行的上一行及下一行系统日志。系统日志的实时提取示例如下。
1) 读取源PS数据集
本部分用来读取源PS数据集中的数据,并且以行为单位将数据读入REXX的STEM变量keyword.中,以备后续处理使用。
KEYINPUT = YOURID.REXX.DATASET /* 源PS数据集 */
KEYINPUT = STRIP(KEYINPUT) /* 移除两边空格 */
/*-------------------------------------------------------------*/
/* 获取源PS数据集中的关键字及其他相关参数 */
/*-------------------------------------------------------------*/
CALL BPXWDYN "ALLOC DA('"KEYINPUT"') FI(INPUT) SHR REUSE"
ADDRESS MVS "EXECIO * DISKR INPUT (STEM keyword. FINIS"
CALL BPXWDYN "FREE FI(INPUT)"
2) 初始化系统变量
初始化以下系统变量以备后续使用。
flag = 0 /* 此变量表示是否匹配到关键字,默认状态下为“否” */
keyline = 0 /* 关键字的数量,默认为0 */
zString = "" /* 标志行参数,默认为空 */
startnum = 1 /* 默认从首行开始提取系统日志 */
3) 确保目标数据集的存在性
本部分用来判断目标数据集是否存在,若其存在,则将其设置为可修改模式以备后续内容的追加,否则将分配一个新数据集,并将其设置为可修改模式。
CALL BPXWDYN "Rtext = SYSDSN("'YOURID.REXX.OUTPUT'")"
If Rtext <> 'OK' then /* 如果目标数据集不存在 */
do
CALL BPXWDYN "ALLOC FI(OUTDD) DA('YOURID.REXX.OUTPUT') NEW CATALOG RECFM(V,B) SPACE(5000,5000) BLKSIZE(27998) REUSE" /* 分配一新数据集 */
CALL BPXWDYN "FREE FI(OUTDD)"
CALL BPXWDYN "ALLOC FI(OUTDD) DA('YOURID.REXX.OUTPUT') MOD REUSE"
/* 设置其为可修改模式 */
end
else /* 如果目标数据集存在 */
CALL BPXWDYN "ALLOC FI(OUTDD) DA('YOURID.REXX.OUTPUT') MOD REUSE"
/* 设置其为可修改模式 */
4) 分离关键字与参数
借助循环从STEM变量keyword.中提取源PS数据集中的各行数据,并将最后一行的关键字及参数信息进行分离。
do forever
do k = 1 To keyword.0 /* 循环处理STEM变量keyword. */
ck_jn = strip(keyword.k) /* 获取含关键字及参数的日志行 */
/*-------------------------------------------------------------*/
/* 找到参数的位置 */
/*-------------------------------------------------------------*/
position = POS('<!---!>',ck_jn) + 7
if position = "7" then /* 如果分隔符'<!---!>'不存在 */
x = y = 0 /* 只提取关键字行 */
else /* 如果分隔符'<!---!>'存在 */
/*-------------------------------------------------------------*/
/* 提取两个参数 */
/*-------------------------------------------------------------*/
do
POStar = POS('<!---!>',ck_jn) - 1
target = strip(substr(ck_jn,1,POStar))
key = strip(substr(ck_jn,position))
x = subword(key,1,1)
y = subword(key,2,1)
end
…………
end
end
5) 提取所需日志行
第一次循环将从系统日志的首行开始来提取所有关键字行,而从第二次循环开始,将只提取标志行之后的系统日志,从而保证写入目标PS数据集数据的完整性及不重复性。
do forever
rc = isfcalls('ON') /* 打开SDSF宿主环境 */
Address SDSF "ISFLOG READ TYPE(SYSLOG)"
if zString <> "" then /* 判断是否首次循环 */
do ix = 1 to isfline.0 /* 定位当次循环的开始位置 */
if isfline.ix = zString then
startnum = ix + 1
end
do ix = startnum to isfline.0 /* 循环读取系统日志 */
if ix = isfline.0 then
zString = Strip(isfline.ix) /* 获取标志行系统日志 */
do i = 1 to keyline /* 循环匹配所有关键字 */
temp = STRIP(keyword.i)
strPos = pos(temp,isfline.ix)
if strPos <> 0 then
do
flag=1 /* 退出当前循环 */
leave i
end
end
if flag = 1 then /* 提取系统日志行 */
do
flag = 0 /* 将其设置为初始状态: false */
cnt = 0 /* 初始化该参数 */
sum = 0 /* 初始化该参数 */
out.0 = 0 /* 初始化该参数 */
/*-------------------------------------------------------------*/
/* 判断’x’是否超出系统日志的范围 */
/*-------------------------------------------------------------*/
if ix <= x then
do
sum = sum + (x - ix) + 1
iz = 1 /* 从第一行开始读取系统日志 */
end
else
do
iz = ix - x /* 从所需行开始读取系统日志 */
end
/*-------------------------------------------------------------*/
/* 获取关键字行周边的所需日志行 */
/*-------------------------------------------------------------*/
out.0 = x + y + 1 - sum
do iy = iz to (iz + x + y - sum)
cnt = cnt + 1
out.cnt = isfline.iy
/*-------------------------------------------------------------*/
/* 判断’iy’是否超出系统日志的范围 */
/*-------------------------------------------------------------*/
if iy >= isfline.0 then
do
out.0 = cnt
/*-------------------------------------------------------------*/
/* 如果’iy’超出系统日志范围,则退出当前循环 */
/*-------------------------------------------------------------*/
leave iy /* 退出当前循环 */
end
end
/*-------------------------------------------------------------*//* 将所需日志行写入目标PS数据集 */
/*-------------------------------------------------------------*/
ADDRESS MVS 'EXECIO' out.0 'DISKW OUTDD (STEM out. FINIS'
end
end
end
CALL BPXWDYN "FREE FI(OUTDD)"
rc = isfcalls('OFF') /* 关闭SDSF宿主环境 */
exit 0 /* 程序结束 */
6) 利用JCL提交脚本
为了便于脚本的自动启动与终止,选择利用JCL来提交脚本。在本文中,脚本被存于YOURID.REXX.POSIX(RDSYSLOG)中。
//YOURJCL JOB 2000,'YOURID',MSGLEVEL=(1,1),MSGCLASS=H,CLASS=J
//DONEOJ EXEC PGM=IKJEFT01,DYNAMNBR=20,TIME=1440
//SYSUDUMP DD SYSOUT=(H,,STD)
//SYSTSPRT DD SYSOUT=(H,,STD)
//SYSTSIN DD *
EX 'YOURID.REXX.POSIX(RDSYSLOG)'
/*
7) 系统日志提取的终止
终止系统日志提取的脚本如下。
/* REXX */
RC=ISFCALLS('ON')
ADDRESS SDSF "ISFEXEC ST"
DO ix=1 to JNAME.0
if pos("YOURJCL",JNAME.ix)=1 then
Address SDSF "ISFACT ST TOKEN('"TOKEN.ix"') PARM(NP P)"
end
RC=ISFCALLS('OFF')
3. 结束语
本文主要介绍了如何使用REXX在z/OS中实时提取系统日志。本文涉及的REXX脚本可以直接运行于USS环境,本脚本与JCL相结合可以进行更多方面的应用。本脚本适用于z/OS中系统日志的实时提取及分析,可应用于银行及证券中心等相关部门。在实际应用中,通过对本示例的演变,还可以解决更大范围及更灵活的系统日志提取与分析问题。
附录
详见附录文件“code.zip”。
参考资料
TSO/E REXX User's Guide
SDSF Operation and Customization
z/OS V2R1 information center
作者:霍战鹏,黄文集
邮箱:huozhanpATcn.ibm.com(替换AT为@)
内容声明:文中专业名词因翻译原因,表述中难免存在差异。如有疑惑,请以英文为准。同时数据源于实验室环境,仅供参考。如果您对我们的话题感兴趣,请通过电子邮箱联系我们。