For several failures issues, I wrote this trigger - audit_failed_trg
as an after servererror on database trigger.
My first thinking was to check only specific exception\user\table according to the need.
But I just wondering - the database should fire this trigger for any failure.
Is that a good idea to enable it in production environment?
Is this can cause any performance problems or others?
I'm using Oracle 11g.
create or replace trigger audit_failed_trg
after servererror on database
declare
l_sql_text ora_name_list_t;
l_n number;
begin
insert into T values ( S.NEXTVAL, 1, 'ora_sysevent = ' || ORA_SYSEVENT ,sysdate);
insert into T values ( S.CURRVAL, 2, 'ora_login_user = ' || ORA_LOGIN_USER,sysdate );
insert into T values ( S.CURRVAL, 3, 'ora_server_error = ' || ORA_SERVER_ERROR(1),sysdate );
insert into T values ( S.CURRVAL, 4, 'SID = ' || SYS_CONTEXT ('USERENV','SID'),sysdate);
insert into T values ( S.CURRVAL, 5, 'host = ' || SYS_CONTEXT ('USERENV','HOST') ,sysdate);
insert into T values ( S.CURRVAL, 6, 'ip = ' || SYS_CONTEXT ('USERENV','IP_ADDRESS') ,sysdate);
insert into T values ( S.CURRVAL, 7, 'module = ' || SYS_CONTEXT ('USERENV','MODULE') ,sysdate);
insert into T values ( S.CURRVAL, 8, 'serverhost = ' || SYS_CONTEXT ('USERENV','SERVER_HOST') ,sysdate);
l_n := ora_sql_txt( l_sql_text );
for i in 1 .. l_n
LOOP
insert into t values ( s.CURRVAL,8+i, 'l_sql_text(' || i || ') = ' || l_sql_text(i),sysdate );
end loop;
end;
Logging all server errors is a good idea and I've seen it work well in production environments.
In theory, error logging is handled by applications. In practice, most applications do not catch all database errors. It's useful to have a single table that contains all errors generated by a database.
However, this kind of trigger has particular challenges that need to be carefully considered:
AFTER SERVERERROR is a safer event, because something has already broken before it was called. But weird things can still happen. For example, you'll notice the exception when others then null; code. That code is usually an anti-pattern, but this is one of the few places where you truly want to suppress all exceptions to avoid an infinite loop.Spend some time on a better table design. Ignore the key-value pair type of table used in the question. Instead, create a table that will store one row per error, and use meaningful names. A table like this will be much, much easier to meaningfully query:
--drop trigger audit_failed_trg;
--drop table server_errors;
--drop sequence server_error_seq;
create sequence server_error_seq;
create table server_errors
(
id number not null,
error_date date not null,
ora_sysevent varchar2(128),
ora_login_user varchar2(128),
ora_server_error varchar2(4000),
sid number,
host varchar2(256),
ip varchar2(15),
module varchar2(4000),
serverhost varchar2(256),
sql clob,
constraint server_errors_pk primary key(id)
);
create or replace trigger audit_failed_trg
after servererror on database
declare
v_sql_text ora_name_list_t;
v_sql clob;
v_n number;
begin
v_n := ora_sql_txt(v_sql_text);
for i in 1 .. v_n loop
v_sql := v_sql || v_sql_text(i);
end loop;
--If you find a huge number of irrelevant errors, you might want to filter them out here.
insert into server_errors
values
(
server_error_seq.nextval,
sysdate,
ora_sysevent,
ora_login_user,
ora_server_error(1),
sys_context ('USERENV','SID'),
sys_context ('USERENV','HOST'),
sys_context ('USERENV','IP_ADDRESS'),
sys_context ('USERENV','MODULE'),
sys_context ('USERENV','SERVER_HOST'),
v_sql
);
commit;
--Never raise an exception from this trigger.
--No matter what happens we don't want recursive errors.
exception when others then
null;
end;
/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With