# MERGElib.ctl: Defines TLmerge Macros # $Id: MERGElib.ctl,v 1.5 2015/02/20 18:44:54 RDA Exp $ # ARCS: $Header: /home/cvs/cvs/RDA_8/src/scripting/lib/collect/DB/MERGElib.ctl,v 1.5 2015/02/20 18:44:54 RDA Exp $ # # Change History # 20150220 KRA Improve list management. =head1 NAME DB:MERGElib - Defines TLmerge Macros =head1 DESCRIPTION This persistent submodule regroups macros that are used by the alert log and the trace file merge tool. =cut # Make the module persistent and share macros keep $KEEP_BLOCK,@SHARE_MACROS var @SHARE_MACROS = ('extract_alert_data','extract_oracm_log',\ 'extract_rac_data','extract_trace_data',\ 'get_asm_context','get_crs_home','merge_files') # Define library constants if ${RDA.B_VMS} {var $RE_ALERT1 = '^\d{2}-[A-Za-z]{3}-\d{4}\s+\ \d{2}:\d{2}:\d{2}\.\d+' var $RE_ALERT2 = '^(\d{2})-([A-Za-z]{3})-(\d{4})\s+\ (\d{2}):(\d{2}):(\d{2})\.\d+' var $RE_CM1 = '\d{2}-[A-Za-z]{3}-\d{4}\s+\ \d{2}:\d{2}:\d{2}\.\d+' var $RE_CM2 = '^(\d{2})-([A-Za-z]{3})-(\d{4})\s+\ (\d{2}):(\d{2}):(\d{2})\.\d+' var $RE_END = '\d{2}-[A-Za-z]{3}-\d{4}\s+\d{2}:\d{2}:\d{2}\.\d+' } else {var $RE_ALERT1 = '^(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s+\w{3}\s+\d+\s+\ \d+:\d+:\d+\s+\d{4}' var $RE_ALERT2 = '^[A-Za-z]{3}\s+([A-Za-z]{3})\s+(\d+)\s+\ (\d+):(\d+):(\d+)\s+(\d{4})' var $RE_CM1 = '{((Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s+\w{3}\s+\d+\s+\ \d+:\d+:\d+\s+\d{4}\s+)}.*' var $RE_CM2 = '[A-Za-z]{3}\s+([A-Za-z]{3})\s+(\d+)\s+\ (\d+):(\d+):(\d+)\s+(\d{4})' var $RE_END = '{(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s+' } var $RE_RAC1 = '^(\[ CSSD\]|)((\d{4}|\d{2})\-(\d{2}|[A-Za-z]{3})\-\ (\d{2}|\d{4})\s+\d{2}:\d{2}:\d{2}\.\d+).*' var $RE_RAC2 = '^(\[ CSSD\]|)(\d{4})\-(\d{2})\-(\d{2})\s+\ (\d{2}):(\d{2}):(\d{2})\.(\d+).*' var $RE_RAC3 = '^(\d{2})\-([A-Za-z]{3})\-(\d{4})\s+\ (\d{2}):(\d{2}):(\d{2})\.(\d+).*' var $RE_TRACE = '^\*{3}\s+\d{4}\-\d{2}\-\d{2}\s+\d{2}:\d{2}:\d{2}\.\d+$' var %tb_mon = ('JAN','01','FEB','02','MAR','03','APR','04','MAY','05',\ 'JUN','06','JUL','07','AUG','08','SEP','09','OCT','10',\ 'NOV','11','DEC','12') keep $RE_ALERT1,$RE_ALERT2,$RE_CM1,$RE_CM2,$RE_END,$RE_RAC1,$RE_RAC2,$RE_RAC3,\ $RE_TRACE keep %tb_mon # ----------------------------------------------------------------------------- # Context detection macros # ----------------------------------------------------------------------------- # Get ASM context macro get_asm_context {# Check if ASM is in use if !${SET.DB.ASM.B_IN_USE:true} return () # Determine the ASM ORACLE_SID var $hom = ${SET.DB.ASM.D_ORACLE_HOME:''} var $asm = ${SET.DB.ASM.T_ORACLE_SID:'*'} if compare('eq',$asm,'*') run DB:ASMinit(\$hom,\$asm) # Switch to the ASM context call setSqlTarget(${SET.DB.ASM.I_DB}) return ($asm,$hom) } # Determine the Oracle CRS home macro get_crs_home {if ${SET.DB.CRS.D_CRS_HOME} return last var $crs run DB:CRSinit(\$crs) return $crs } # ----------------------------------------------------------------------------- # Merge routines # ----------------------------------------------------------------------------- # Adjust the time stamp macro adjust_record {var ($rec,$off) = @arg var (undef,$tim,$dat) = split('\|',$rec,3) var ($yea,$mon,$day,$hou,$min,$sec) = \ match($tim,'^(....)(..)(..) (..)(..)(..\....)$') incr $sec,$off if or(expr('<',$sec,0),expr('>=',$sec,60)) {decr $mon var ($sec,$msc) = frac($sec,true) var $tim = concat(localtime('%Y%m%d %H%M%S',\ mktime($sec,$min,$hou,$day,$mon,$yea)),substr(sprintf('%.3f',$msc),1)) } else var $tim = concat($yea,$mon,$day,' ',$hou,$min,sprintf('%06.3f',$sec)) return (concat('|',$tim,'|',$dat),$tim) } # Get the buffers having two lowest time stamp values macro min_timestamp {var (\%tim) = @arg var ($buf1,$buf2,@buf) = keys(%tim) if !defined($buf2) return ($buf1) if compare('lt',$tim{$buf1},$tim{$buf2}) var ($min1,$min2) = ($buf1,$buf2) else var ($min1,$min2) = ($buf2,$buf1) loop $buf (@buf) {var $tim = $tim{$buf} if compare('le',$tim,$tim{$min1}) var ($min1,$min2) = ($buf,$min1) elsif compare('lt',$tim,$tim{$min2}) var $min2 = $buf } return ($min1,$min2) } # Merge extracted data macro merge_files {var ($set,$nod,\@tmp,\%off,$del) = @arg var @buf = ('BUF0','BUF1','BUF2','BUF3','BUF4','BUF5','BUF6','BUF7') var $flg = @tmp while $flg {var (%fil,%rec,%tim) = () for $i (0,7) {var $fil = shift(@tmp) break !defined($fil) var $key = $buf[$i] call createBuffer($key,'R',$fil) var $rec = chomp(getLine($key)) var $del{$key} = basename($fil) var $dlt{$key} = $off{$fil} if $dlt{$key} var ($rec{$key},$tim{$key}) = adjust_record($rec,last) else var ($rec{$key},$tim{$key}) = ($rec,field('\|',1,$rec)) } if scalar(@tmp) call $[OUT]->add_report('S',sprintf('%s_%06d',$set,last),0,'.txt') else call $[OUT]->add_report('E',concat($nod,'_',$set),0,'.txt') var $num = keys(%tim) while expr('>',$num,1) {var ($min1,$min2) = min_timestamp(\%tim) var $tim = $tim{$min1} var $nxt = $tim{$min2} while compare('le',$tim,$nxt) {write $rec{$min1} if getLine($min1) {var $rec = chomp(last) if $dlt{$min1} var ($rec{$min1},$tim) = adjust_record($rec,last) else var ($rec{$min1},$tim) = ($rec,field('\|',1,$rec)) var $tim{$min1} = $tim } else {delete $tim{$min1} call deleteBuffer($min1) if $del call purge('s',verbatim($del{$min1}),-1) decr $num break } } } if $num {var ($min1) = keys(%tim) write $rec{$min1} while getLine($min1) {var $rec = chomp(last) if $dlt{$min1} var ($rec) = adjust_record($rec,last) write $rec } delete $tim{$min1} call deleteBuffer($min1) if $del call purge('s',verbatim($del{$min1}),-1) } call push(@tmp,getFile('/')) var $lst = getFile('.') close var $flg = expr('>',scalar(@tmp),1) } # Indicate the merge file return $lst } # ----------------------------------------------------------------------------- # Alert log parsing routines # ----------------------------------------------------------------------------- # Detect the first relevant alert log record if ${RDA.B_VMS} {macro check_alert {var ($lin,$beg) = @arg import $RE_ALERT2 keep $RE_ALERT2 var ($day,$mon,$yea,$hou,$min,$sec) = match($lin,$RE_ALERT2) var $val = difftime(mktime($sec,$min,$hou,$day,$mon,$yea),$beg) if expr('<',$val,0) return -1 call parseKeep() return 1 } } else {macro check_alert {var ($lin,$beg) = @arg import $RE_ALERT2 keep $RE_ALERT2 var ($mon,$day,$hou,$min,$sec,$yea) = match($lin,$RE_ALERT2) var $val = difftime(mktime($sec,$min,$hou,$day,$mon,$yea),$beg) if expr('<',$val,0) return -1 call parseKeep() return 1 } } # Detect the first relevant cm log record if ${RDA.B_VMS} {macro check_cm {var ($lin,$beg) = @arg import $RE_CM2 keep $RE_CM2 var ($day,$mon,$yea,$hou,$min,$sec) = match($lin,$RE_CM2) var $val = difftime(mktime($sec,$min,$hou,$day,$mon,$yea),$beg) if expr('<',$val,0) return -1 call parseKeep() return 1 } } else {macro check_cm {var ($lin,$beg) = @arg import $RE_CM2 keep $RE_CM2 var ($mon,$day,$hou,$min,$sec,$yea) = match($lin,$RE_CM2) var $val = difftime(mktime($sec,$min,$hou,$day,$mon,$yea),$beg) if expr('<',$val,0) return -1 call parseKeep() return 1 } } # Detect the first relevant cluster log record macro check_rac {var ($lin,$beg) = @arg var ($yea,$mon,$day,$hou,$min,$sec) = split('\s+|:|-|\.',$lin) decr $mon var $val = difftime(mktime($sec,$min,$hou,$day,$mon,$yea),$beg) if expr('<',$val,0) return -1 call parseKeep() return 1 } # Detect the first relevant trace record macro check_trace {var ($lin,$beg) = @arg var (undef,$yea,$mon,$day,$hou,$min,$sec) = split('\s+|:|-|\.',$lin) decr $mon var $val = difftime(mktime($sec,$min,$hou,$day,$mon,$yea),$beg) if expr('<',$val,0) return -1 call parseKeep() return 1 } # Initiate the alert log data extraction if ${RDA.B_VMS} {macro start_alert {var ($lin,$end,\$cur) = @arg import $RE_ALERT2,%tb_mon keep $RE_ALERT2,%tb_mon var ($day,$mon,$yea,$hou,$min,$sec) = match($lin,$RE_ALERT2) var $cur = sprintf('%s%s%02d %s%s%s.000',\ $yea,$tb_mon{uc($mon)},$day,$hou,$min,$sec) var $val = difftime(mktime($sec,$min,$hou,$day,$mon,$yea),$end) if expr('>',$val,0) call parseQuit() } } else {macro start_alert {var ($lin,$end,\$cur) = @arg import $RE_ALERT2,%tb_mon keep $RE_ALERT2,%tb_mon var ($mon,$day,$hou,$min,$sec,$yea) = match($lin,$RE_ALERT2) var $cur = sprintf('%s%s%02d %s%s%s.000',\ $yea,$tb_mon{uc($mon)},$day,$hou,$min,$sec) var $val = difftime(mktime($sec,$min,$hou,$day,$mon,$yea),$end) if expr('>',$val,0) call parseQuit() } } # Initiate the cm log data extraction if ${RDA.B_VMS} {macro start_cm {var ($lin,$end,\$cur) = @arg import $RE_CM2,%tb_mon keep $RE_CM2,%tb_mon var ($day,$mon,$yea,$hou,$min,$sec) = match($lin,$RE_CM2) var $cur = sprintf('%s%s%02d %s%s%s.000',\ $yea,$tb_mon{uc($mon)},$day,$hou,$min,$sec) var $val = difftime(mktime($sec,$min,$hou,$day,$mon,$yea),$end) if expr('>',$val,0) call parseQuit() } } else {macro start_cm {var ($lin,$end,\$cur) = @arg import $RE_CM2,%tb_mon keep $RE_CM2,%tb_mon var ($mon,$day,$hou,$min,$sec,$yea) = match($lin,$RE_CM2) var $cur = sprintf('%s%s%02d %s%s%s.000',\ $yea,$tb_mon{uc($mon)},$day,$hou,$min,$sec) var $val = difftime(mktime($sec,$min,$hou,$day,$mon,$yea),$end) if expr('>',$val,0) call parseQuit() } } # Initiate the cluster log data extraction macro start_rac {var ($lin,$end,\$cur) = @arg import $RE_RAC2,$RE_RAC3 keep $RE_RAC2,$RE_RAC3 if match($lin,$RE_RAC2) {var (undef,$yea,$mon,$day,$hou,$min,$sec,$msc) = (last) var $cur = join('',$yea,$mon,$day,' ',$hou,$min,$sec,'.',$msc) decr $mon } elsif match($lin,$RE_RAC3) {var ($day,$mon,$yea,$hou,$min,$sec) = (last) var $cur = sprintf('%s%s%02d %s%s%s.000',\ $yea,$tb_mon{uc($mon)},$day,$hou,$min,$sec) } var $val = difftime(mktime($sec,$min,$hou,$day,$mon,$yea),$end) if expr('>',$val,0) call parseQuit() } # Initiate the trace data extraction macro start_trace {var ($lin,$end,\$cur,\%flg) = @arg var (undef,$yea,$mon,$day,$hou,$min,$sec,$msc) = split('\s+|:|-|\.',$lin) var $cur = join('',$yea,$mon,$day,' ',$hou,$min,$sec,'.',$msc) var %flg = () decr $mon var $val = difftime(mktime($sec,$min,$hou,$day,$mon,$yea),$end) if expr('>',$val,0) call parseQuit() } # Extract the alert log information macro end_alert {var ($cur,$nod,$typ,$fil) = @arg import $RE_END keep $RE_END if $cur {var ($tps,@buf) = parseBuffer() var $cnt = @buf if match($buf[-1],$RE_END) {delete $buf[-1] decr $cnt } if $cnt write '|',$cur,'|',$nod,'|',$typ,'|',encode($fil),'|``',replace(replace(\ join('%BR%',@buf),'\|','|',true),'\*','*',true),'``|' } } # Extract the cluster log information macro end_cm {var ($cur,$nod,$typ,$fil) = @arg import $RE_END keep $RE_END if $cur {var (@buf) = parseBuffer() var $cnt = @buf if match($buf[-1],$RE_END) {delete $buf[-1] decr $cnt } if $cnt write '|',$cur,'|',$nod,'|',$typ,'|',encode($fil),'|``',replace(replace(\ join('%BR%',@buf),'\|','|',true),'\*','*',true),'``|' } } # Extract the cluster log information macro end_rac {var ($cur,$nod,$typ,$fil) = @arg if $cur {var (@buf) = parseBuffer() var $cnt = @buf if $cnt write '|',$cur,'|',$nod,'|',$typ,'|',encode($fil),'|``',replace(replace(\ join('%BR%',@buf),'\|','|',true),'\*','*',true),'``|' } } # Extract the trace information macro end_trace {var ($cur,$nod,$typ,$fil,\@buf,\%flg) = @arg if @buf {var $cnt = parseCount() if $cnt call push(@buf,concat('(',$cnt,' more lines in trace file)')) if $flg{'SYS'} call push(@buf,'(contains System State Dump)') if $flg{'PRC'} call push(@buf,'(contains Process State Dump)') if $flg{'HPD'} call push(@buf,'(contains Heap Dump)') write '|',$cur,'|',$nod,'|',$typ,'|',encode($fil),'|``',replace(replace(\ join('%BR%',@buf),'\|','|',true),'\*','*',true),'``|' } } # ----------------------------------------------------------------------------- # Data extraction macros # ----------------------------------------------------------------------------- # Extract data from alert log files macro extract_alert_data {var ($set,$beg,$end,$cnt,$typ,@fil) = @arg import $RE_ALERT1 keep $RE_ALERT1 # Initialize the parser call parseReset() call parseInfo('TOP','ini','BEG') call parsePattern('BEG',$RE_ALERT1,code(check_alert(line,$beg))) call parseBegin('TOP',$RE_ALERT1,'REC','GRP1') call parseInfo('REC','buf',-1) call parseInfo('REC','beg',code(start_alert(line,$end,\$cur))) call parseInfo('REC','end',code(end_alert($cur,${RDA.T_NODE},$typ,$fil))) # Extract the information loop $fil (@fil) {next !?testFile('r',$fil) # Reject a file that has not been modified after the start time var $val = difftime(getLastModify($fil),$beg) next expr('<',$val,0) # Analyze the file debug ' - Analyzing ',$fil call $[OUT]->add_report('S',sprintf('%s_%06d',$set,$cnt),0,'.tmp') call createBuffer('BUF','R',$fil) var $cur = undef var $fil = basename($fil) call parse('BUF') call deleteBuffer('BUF') if isCreated() incr $cnt close } # Return the new counter value return $cnt } # Extract data from 'oracm' log files macro extract_oracm_log {var ($set,$beg,$end,$cnt,$typ,@fil) = @arg import $RE_CM1 keep $RE_CM1 # Initialize the parser call parseReset() call parseInfo('TOP','ini','BEG') call parseInfo('TOP','trc','BEG') call parsePattern('BEG',$RE_CM1,code(check_cm(line,$beg))) call parseBegin('TOP',$RE_CM1,'REC','GRP1') call parseInfo('REC','buf',-1) call parseInfo('REC','beg',code(start_cm(line,$end,\$cur))) call parseInfo('REC','end',code(end_cm($cur,${RDA.T_NODE},$typ,$fil))) # Extract the information loop $fil (@fil) {next !?testFile('r',$fil) # Reject a file that has not been modified after the start time var $val = difftime(getLastModify($fil),$beg) next expr('<',$val,0) # Analyze the file debug ' - Analyzing ',$fil call $[OUT]->add_report('S',sprintf('%s_%06d',$set,$cnt),0,'.tmp') call createBuffer('BUF','R',$fil) var $cur = undef var $fil = basename($fil) call parse('BUF') call deleteBuffer('BUF') if isCreated() incr $cnt close } # Return the new counter value return $cnt } # Extract data from cluster log files macro extract_rac_data {var ($set,$beg,$end,$cnt,$typ,@fil) = @arg import $RE_RAC1 keep $RE_RAC1 # Initialize the parser call parseReset() call parseInfo('TOP','ini','BEG') #call parseInfo('TOP','trc','BEG') call parsePattern('BEG',$RE_RAC1,code(check_rac(parseHit(1),$beg))) call parseBegin('TOP',$RE_RAC1,'REC','GRP1') call parseInfo('REC','buf',-1) call parseInfo('REC','beg',code(start_rac(line,$end,\$cur))) call parseInfo('REC','end',code(end_rac($cur,${RDA.T_NODE},$typ,$fil))) # Extract the information loop $fil (@fil) {next !?testFile('r',$fil) # Reject a file that has not been modified after the start time var $val = difftime(getLastModify($fil),$beg) next expr('<',$val,0) # Analyze the file debug ' - Analyzing ',$fil call $[OUT]->add_report('S',sprintf('%s_%06d',$set,$cnt),0,'.tmp') call createBuffer('BUF','R',$fil) var $cur = undef var $fil = basename($fil) call parse('BUF') call deleteBuffer('BUF') if isCreated() incr $cnt close } # Return the new counter value return $cnt } # Extract data from trace files macro extract_trace_data {var ($set,$beg,$end,$cnt,$typ,@fil) = @arg import $MERGE_LINES,$RE_TRACE keep $MERGE_LINES,$RE_TRACE # Initialize the parser var $max = nvl($MERGE_LINES,10) incr $max call parseReset() call parseInfo('TOP','ini','BEG') call parseBegin('TOP',$RE_TRACE,'REC/BUF','GRP1') call parsePattern('BEG',$RE_TRACE,code(check_trace(line,$beg))) call parseInfo('BUF','buf',-1) call parseInfo('BUF','max',$max) call parseInfo('BUF','beg',code(start_trace(line,$end,\$cur,\%flg))) call parseInfo('BUF','end',code((undef,@buf) = parseBuffer())) call parseInfo('REC','end',\ code(end_trace($cur,${RDA.T_NODE},$typ,$fil,\@buf,\%flg))) call parsePattern('BUF',\ '^SYSTEM STATE$', code($flg{'SYS'} = 1,-1),\ '^PROCESS STATE$', code($flg{'PRC'} = 1,-1),\ 'HEAP\s+DUMP\s+heap\s+name=.*desc=',code($flg{'HPD'} = 1,-1)) call parsePattern('REC',\ '^SYSTEM STATE$', code($flg{'SYS'} = 1,-1),\ '^PROCESS STATE$', code($flg{'PRC'} = 1,-1),\ 'HEAP\s+DUMP\s+heap\s+name=.*desc=',code($flg{'HPD'} = 1,-1)) # Treat the files loop $fil (@fil) {next !?testFile('r',$fil) # Reject a file that has not been modified after the start time var $val = difftime(getLastModify($fil),$beg) next expr('<',$val,0) # Analyze the file debug ' - Analyzing ',$fil call $[OUT]->add_report('S',sprintf('%s_%06d',$set,$cnt),0,'.tmp') call createBuffer('BUF','R',$fil) var $cur = undef var $fil = basename($fil) call parse('BUF') call deleteBuffer('BUF') if isCreated() incr $cnt close } return $cnt } =head1 SEE ALSO L, L =head1 COPYRIGHT NOTICE Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. =head1 TRADEMARK NOTICE Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners. =cut