Oracle FAQ | Your Portal to the Oracle Knowledge Grid |
![]() |
![]() |
Home -> Community -> Usenet -> c.d.o.misc -> Re: Freebie: read/grep alert log from sqlplus
I wrote something similar but in Perl. It runs as a crontab-job and scans
all alert-log files on a machine every hour and mails any error found.
I wrote this tool when we had problem with the intelligent agent and had
to check alert-logs on different machines with different OS (unix, openvms).
The scanning of the alert-logs is sequential but it is still fast (on hour
machines
at least). The script expects the alert-log files in OFA complaint directory:
/u01/app/oracle/admin/<INSTANCENAME>/bdump/alert_<INSTANCENAME>.log
To scheduled the script I use :
0 0-23 * * * (cd Alert; ./alert_log.pl) > /dev/null
#! By I. Saez: Looks for ora- errors in alert-log
#! Oracle instances. Range is between current date and hour and previous hour
(and date)
#! date format Oracle in alert-log : Thu Aug 2 16:34:27 MET DST 2001
#!
$mailprog = "/usr/lib/sendmail -t -oi"; # email-program
$mailto = "i.a.saez.scheihing\@tue.nl"; # change to your email
$subject = "Errors found in";
$from = "i.a.saez.scheihing\@tue.nl";
$cc = "";
$date = `date`;
$adebug = 0; # set to 1 for debug info
chop($date);
$date = substr($date,0,index($date,":")-2); # example: Tue May 28
$hour = `date +'%H'`; # example: 07
chop($hour);
$now = $date.$hour; # Tue May 28 07
# hour = 0
if ($hour == 0 ) {
# 12 o'clock in the evening; go one day back $hour = 23; # previous day ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time-86400); $y+=1900; $mon = (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec)[$mon]; $dag = (Sun,Mon,Tue,Wed,Thu,Fri,Sat)[$wday]; $date = ( $mday < 10 ) ? $dag.' '.$mon.' '.$mday : $dag.' '.$mon.''.$mday;
}
else {
$hour = $hour - 1
}
# previous hour
if ( $hour < 10 ) {
$prev = $date.'0'.$hour;
} else {
$prev = $date.$hour;
}
$nodenaam = `hostname`;
#
open ORA,"/var/opt/oracle/oratab" || die "Can't open /var/opt/oracle/oratab";
while (<ORA>) {
# read all instance names
chop;
# print $_;
if ( /#/ || /^$/ ) {
# skip comment and empty lines
} else {
# get instance name
( $inst,$home,$start) = split(/:/);
# Alert log-file name plus path; works only if OFA is used!!!
$alert_log = "/u01/app/oracle/admin/$inst/bdump/alert_$inst.log";
#
if ($adebug) {
print qq|
Alert log : $alert_log Hour : $hour now : $now Prev : $prev
&CHECK_LOG( $alert_log,$inst);
#
} # if (index($_,"#") ) {
} # while (<ORA>) {
close ORA;
exit;
sub CHECK_LOG ()
{
# scan alert_log between now ($now) and one hour back ($prev)
print qq|
Scanning alert file $alert_log of instance $inst
between "$prev" en "$now"
|;
$i = 0; $mailbool = 0; $bool = 0;
chop;
if ( /$prev/ || $bool ) {
# here scan for ora- errors if ( /ORA-/ || /Errors in/ ) { $mailbool = 1; $mailarr{$j++} = $_; } # if ( /ORA-/ ) { $bool = 1; # keep scanning
} #if ( /$prev/ || $bool ) {
if ( /$now/ ) {
$bool = 0; # no more scanning $last;
$i++;
} # while (<IN> ) {
&Mail_errors() if $mailbool;
print qq|
$i lines scanned
|;
close (IN);
}
sub Mail_errors () {
print "in Mail_errors\n";
open ( MAIL,"|${mailprog} " ) || die "can't open $mailprog!";;
print MAIL "To: ${mailto}\r\n"; print MAIL "Cc: ${cc}\r\n"; print MAIL "From: ${from}\r\n"; print MAIL "Subject: $subject $alert_log!\r\n"; print MAIL "\r\n"; print MAIL "Between $prev and $now \r\n";foreach $key ( sort keys %mailarr ) {
} # end sub Mail_errors
Steve Perry wrote:
> I thought this might be useful to somebody. I wrote it (with help from > metalink and akadia) because I hated having to telnet to different servers > to look at the alert log. save it off in directory, start sqlplus and type > @alertlog. It will show you filtered errors in it. If you don't manage the > alertlogs and archive them weekly or monthly, this can take a bit to run. On > my systems, it takes a few seconds. I'm almost done converting it to a > package with more features (i.e. date range, you don't have keep creating > the directory). It does require v8.0+ and the utl_raw package. Other than > that, it should work just fine. > > If you see areas for improvement, let me know. > > Steve > > rem clear screen > set echo off > set lines 150 > set arraysize 120 > > -- > * ------------------------------------------------------------------------ * > -- * @alertlog > * > -- * FILE: alertlog.sql > * > -- * SOURCE: "glued" together code from metalink, akadia and my own > * > -- * AUTHOR: Steve Perry and above mentioned caveats. > * > -- * EMAIL : sperry_at_sprynet.com > * > -- * DATE : 3/15/02 > * > -- * INPUT : none > * > -- * OUTPUT: report > * > -- * ORACLE: 8.0.x and above. > * > -- * Restrictions: assumes the path is "hardcoded" and no env vars. > * > -- * DESCRIPTION: displays info about errors and things of interest in the > * > -- * database alert log. > * > -- * > * > -- * Maintenance > * > -- * SMP 3/15/02 Created, * > -- * smp 3/18/02 modified for Unix support and alertlog > default* > -- * names: Unix : alert_<sid>.log * > -- * Windows: <sid>ALRT.LOG * > -- * > * > -- > * ------------------------------------------------------------------------ * > > set verify off > set feedback off > > --Determine the OS (WIN or UNIX) > col OS_PLATFORM new_value OS_PLATFORM noprint > select decode(instr(upper(product), 'WINDOWS',1), 0 , 'UNIX', 'WINDOWS') > OS_PLATFORM > from PRODUCT_COMPONENT_VERSION > WHERE upper(PRODUCT) LIKE 'TNS%' > / > > col dirname new_value dirname noprint > select decode('&OS_PLATFORM', 'WINDOWS', value || '\', value || '/') dirname > from v$parameter > where name = 'background_dump_dest' > / > > -- debug stuff > -- prompt dir = &&dirname > > create or replace directory "ALERTDIR" as '&&dirname'; > > --allows leading whitespace to be printed by dbms_output > SET SERVEROUTPUT ON FORMAT WRAPPED > > rem clear screen > > -- **************************************************************** > -- BEGIN CODE PART > -- **************************************************************** > > DECLARE > -- Input Directory as specified in create directory > l_dir CONSTANT VARCHAR2(30) := 'ALERTDIR'; > > -- Input File which is read word by word > l_fil VARCHAR2(30) ; > l_fil_size number; > > -- Separator Character between words is a BLANK (ascii = 32) > l_sep CONSTANT RAW(500) := UTL_RAW.CAST_TO_RAW(CHR(32)); > l_eol CONSTANT RAW(500) := UTL_RAW.CAST_TO_RAW(CHR(10)); > > -- Character at the end of the file is NEWLINE (ascii = 10) > l_sen CONSTANT RAW(500) := UTL_RAW.CAST_TO_RAW(CHR(10)); > > -- Pointer to the BFILE > l_loc BFILE; > --l_mode_RO BINARY_INTEGER := file_readonly; > > -- Current position in the file (file begins at position 1) > l_pos NUMBER := 1; > > -- Amount of characters have been read > l_read_amt BINARY_INTEGER := 0; > > -- Read BufferS > l_rawbuf raw(500); > l_buf VARCHAR2(500); > > -- End of the current line which will be read > l_end NUMBER; > > -- Return value > l_ret BOOLEAN := FALSE; > > -- DB Name to resolve alert log > l_ora_sid varchar2(30); > > -- work date var > l_date date; > > --alert string > l_alrt varchar2(10); > > --debug setting > bDebug boolean := FALSE; > > --OS PLATFORM > l_OS_PLATFORM varchar2(15) := 'WINDOWS'; > > BEGIN > -- set the max buffer size > dbms_output.enable(1000000); > > --get database name > select value into l_ora_sid from sys.v_$parameter where name = > 'db_name'; > > --Determine the OS (WIN or UNIX) > select decode(instr(upper(product), 'WINDOWS',1), 0 , 'UNIX', 'WINDOWS') > into l_OS_PLATFORM > from sys.PRODUCT_COMPONENT_VERSION > WHERE upper(PRODUCT) LIKE 'TNS%'; > > --set the alert file name now > if l_OS_PLATFORM = 'WINDOWS' then > l_fil := l_ora_sid || 'ALRT.LOG'; > else > l_fil := 'alert_' || l_ora_sid || '.log'; > end if; > > -- Mapping the physical file with the pointer to the BFILE > l_loc := BFILENAME(l_dir,l_fil); > > dbms_output.put_line('File: ALERTLOG.SQL - Compliments of SQL*Buddy > (Steve Perry)...' ); > dbms_output.put_line('Date: ' || to_char(sysdate, 'DY, MON DD HH24:MI:SS > YYYY') ); > dbms_output.put_line('Processing alert.log for sid: ' || l_ora_sid ); > dbms_output.put_line('Opening File ' || l_fil || ' in Directory ' || > l_dir ); > > -- Check if the file exists > l_ret := DBMS_LOB.FILEEXISTS(l_loc) = 1; > IF (l_ret) THEN > -- Open the file in READ_ONLY mode > -- DBMS_LOB.OPEN(l_loc, DBMS_LOB.LOB_READONLY); > DBMS_LOB.FILEOPEN(l_loc, DBMS_LOB.file_readonly ); > > l_fil_size := DBMS_LOB.GETLENGTH( l_loc ); > dbms_output.put_line('Alert log size is: ' || > ltrim(to_char(l_fil_size, '999,999,999,999,999')) || ' bytes.' || chr(10)); > > --print heading > dbms_output.put_line(chr(10) || 'Date > Description'); > > bms_output.put_line('------------------------- -------------------------- > --------------------------------------'); > > /**************/ > LOOP > /*************/ > -- find the end of the current line > l_end := DBMS_LOB.INSTR(l_loc,l_eol,l_pos,1); > -- Process end-of-file > --only goes into here if: reached end of file l_end = 0 > IF (l_end = 0) THEN > l_end := DBMS_LOB.INSTR(l_loc,l_eol,l_pos,1); > l_read_amt := l_end - l_pos - 1; > --debug stuff > IF bDebug then > dbms_output.put_line(' --------------- ' ); > dbms_output.put_line('l_fil_size: ' || to_char(l_fil_size, > '999,999,999,999') ); > dbms_output.put_line('l_end: ' || to_char(l_end , > '999,999,999,999')); > dbms_output.put_line('l_read_amt: ' || to_char(l_read_amt , > '999,999,999,999')); > dbms_output.put_line('l_pos: ' || to_char(l_pos , > '999,999,999,999')); > dbms_output.put_line('l_rawbuf: ' || > UTL_RAW.CAST_TO_VARCHAR2(l_rawbuf) ); > dbms_output.put_line(' --------------- ' ); > --debug stuff > -- DBMS_LOB.READ(l_loc,l_read_amt,l_pos,l_rawbuf); > -- l_buf := UTL_RAW.CAST_TO_VARCHAR2(l_rawbuf); > -- dbms_output.put_line(l_buf); > EXIT; > END IF; > END IF; > > --set chunk of data to read > l_read_amt := l_end - l_pos; > -- Read until end-of-file > DBMS_LOB.READ(l_loc,l_read_amt,l_pos,l_rawbuf); > > --debug stuff > -- if bDebug then > -- dbms_output.put_line(' --------------- ' ); > -- dbms_output.put_line('l_end: ' || to_char(l_end , > '999,999,999,999')); > -- dbms_output.put_line('l_read_amt: ' || to_char(l_read_amt , > '999,999,999,999')); > -- dbms_output.put_line('l_pos: ' || to_char(l_pos , > '999,999,999,999')); > -- dbms_output.put_line(' --------------- ' ); > -- --debug stuff > -- end if; > > --convert the line to character data > l_buf := UTL_RAW.CAST_TO_VARCHAR2(l_rawbuf); > --if win os, strip off the chr(12), otherwise leave it alone. > if l_OS_PLATFORM = 'WINDOWS' then > l_buf := substr(l_buf, 1, length(l_buf) - 1); > end if; > > --hack to find the date (line prior to error) > if substr(l_buf, 4,1) = ' ' then > begin > -------select to_date('Tue Mar 12 03:24:18 2002', 'DY, MON > DD HH24:MI:SS YYYY') from dual > select to_date(l_buf, 'DY, MON DD HH24:MI:SS YYYY') into > l_date from dual; > exception > when others then > l_date := null; > end; > end if; > IF instr(l_buf,'ORA-' , 1 ) > 0 > or instr(l_buf,'Starting up ORACLE' , 1 ) > 0 > or instr(l_buf,'Shutting down instance', 1 ) > 0 > or instr(l_buf,'Errors in' , 1 ) > 0 > or instr(l_buf,'alter database ' , 1 ) > 0 > or instr(l_buf,'Completed: alter data' , 1 ) > 0 then > --hilight errors... > if instr(l_buf, 'ORA-', 1) > 0 then > l_buf := ' !! ' || ltrim(l_buf); > l_alrt := chr(10); > else > l_buf := ' ' || ltrim(l_buf); > l_alrt := ''; > end if; > dbms_output.put_line(l_alrt || to_char(l_date, 'DY, MON DD > HH24:MI:SS YYYY') || l_buf); > -- dbms_output.put_line(' - ' || l_buf); > END IF; > --move pointer to next part of data > l_pos := l_pos + l_read_amt + 1; > IF l_pos > l_fil_size THEN > exit; > END IF; > /***********/ > END LOOP; > /***********/ > --close the file normally > DBMS_LOB.FILECLOSE(l_loc); > dbms_output.put_line( chr(10) || chr(10) ); > ELSE > dbms_output.put_line(chr(10) || 'File ' || l_fil || ' in Directory ' > || l_dir || ' was NOT FOUND' || chr(10)); > END IF; > > EXCEPTION > WHEN OTHERS THEN > dbms_output.put_line('Error: ' || SQLERRM); > DBMS_LOB.FILECLOSE(l_loc); > END; > / > > drop directory "ALERTDIR" > / > > set verify off > set feedback on > set echo onReceived on Tue May 28 2002 - 00:47:28 CDT
![]() |
![]() |