Christopher Poole Oracle Database Consultancy
DBA Tips
Home My CV Applications Tips About
     
 
31 Oct 2007 - DBA_JOB_ERRORS view      
       

/*
-- Creating an external table that points to the alert log is a
-- common trick amongst DBAs, allowing you to read the log
-- without having to open an OS session and giving you the query
-- power of SQL against the log contents.
--
-- This tip is an example of just how powerful this trick can be.
-- Here the alert log is read and parsed for errors created by
-- database jobs (either the new DBMS_SCHEDULER jobs or old style DBMS_JOB jobs).
--
-- This is useful because the behaviour of a job queue process is to dump
-- any unhandled exception that interrupts the process into the alert log (as well as a trace
-- file for the job queue process), not into any database table or v$ view as one would expect.
-- (however new style DBMS_SCHEDULER jobs do also put the error number on the
-- DBA_SCHEDULER_JOB_RUN_DETAILS view).
--
-- As we know the format of the error text placed in the alert log
-- by the job queue processes, we can use analytic functions to
-- extract the error entry and present it as a one row per error
-- in a view.
--
-- The format of an error stack entry in the log created by a job queue process is:
--
-- Dy Mon DD hh24:mi:ss yyyy (a datetime entry common to all alert log entries)
-- Errors in file <name of trace file generated note the trailing colon>:
-- ORA-12012: error on auto execute of job X (this indicates that this entry was from a job)
-- ORA-?????: the first line of the error stack
-- <then any number of lines depending the size of the error stack>
-- Dy Mon DD hh24:mi:ss yyyy (the datetime of the next entry in the alert log)
--
-- From this we can parse out:
-- The time of the error
-- The name of the trace file generated
-- The job number (so we can link to dba_jobs)
-- The exception text raised by the job
-- And possibly other parts of the error stack
--
-- By creating a view from this query, we can now just query it
-- to see if any jobs encountered errors.
-- This code has been tested and works as intended on:
-- 9.2.0.5, 10.1.0.4 and 10.2.0.3.
--
*/



create or replace view dba_job_errors as
select
/* 40 chars is the length of:
'ORA-12012: error on auto execute of job '
leaving us with a job number! */
to_number(trim(substr(job_error_line,40))) as job,
/* turn the datetime of the entry into a date using the observed
format mask used by the alert log */
to_date(error_date, 'Dy Mon DD hh24:mi:ss yyyy') as error_date,
/* extract the file name:
15 is the length of 'Errors in file ', so the file name starts at 16
take off the trailing colon,
l is returned by the query from v$parameter below, add 1
to get the start of the file name
finally substr to 64 chars so our column isn't too wide
*/
substr(substr(rtrim(substr(trace_file_line,16),':'),l+1),1,64) as trace_file,
/* no parsing here, just substr to make the column a suitable width */
substr(the_error,1,128) as error_line1,
/* depending on which line was found to be the last one, either show the line
as a column or null it out
*/
substr(
( case
when (last_line <= 2) then '' else error_2
end
),1,128
) as error_line2,
substr(
( case
when (last_line <= 3) then '' else error_3
end
),1,128
) as error_line3,
substr(
( case
when (last_line <= 4) then '' else error_4
end
),1,128
) as error_line4
from
( /* subscaler query to get the lines from the log using
lag and lead analytics to transform rows into columns */
select
/* don't actually use line_number but might be useful */
line_number,
/* the line two before is the datetime of the entry and therefore
when the error occurred */
lag(text,2) over (order by line_number) as error_date,
/* the line immediately before is the trace file name */
lag(text,1) over (order by line_number) as trace_file_line,
/* this is the line containing the ORA-12012 */
text as job_error_line,
/* the line immediately after is the exception encountered */
lead(text,1) over (order by line_number) as the_error,
/* following lines may or may not be part of the error stack
there is no reason why this could not be extended to cope with huge error
stacks, by just adding more columns with lead(text, X) */
lead(text,2) over (order by line_number) as error_2,
lead(text,3) over (order by line_number) as error_3,
lead(text,4) over (order by line_number) as error_4,
/* if any of the leading text lines is like a datetime entry
then we know which line is the last line of our stack
10g could use REGEXP_LIKE here */
case
when (lead(text,2) over (order by line_number) like '___ ___ __ __:__:__ ____')
then 2
when (lead(text,3) over (order by line_number) like '___ ___ __ __:__:__ ____')
then 3
when (lead(text,4) over (order by line_number) like '___ ___ __ __:__:__ ____')
then 4
/* didn't find the next datetime in our lines so all lines are part of this errorstack */
else 5
end as last_line
from
/* the external table that points to our alert log */
alert_log
),
( /*
Sub scaler query to get the location of the trace files
generated so we can parse out the file name.
Beware, Windows actually puts job trace files
in the user_dump_dest location but we are only interested
in the length of the value, they should be the same,
assuming a convention of ..admin[/|\]sid[/|\][u|b|c|a]dump
Here we note that the path as shown in v$parameter
contains a trailing file seperator. If your entry
doesn't have this, you will have add one to this value,
eg: select length(value)+1 as l...
*/
select length(value) as l from v$parameter where name = 'background_dump_dest'
)
where
/* only interested in job errors
this is cartesian join as there is no link between the two queries
but thats OK as the v$parameter subscaler query only ever returns 1 row
*/
job_error_line like 'ORA-12012: error on auto execute of job%'
/



 

 

     
       
 

 


Copyright © Christopher Poole
31 May 2007
Disclaimer