2009-02-11 1 views
5

Я пытаюсь зарегистрировать все ошибки в моей базе данных в таблице. Так как пользовательский SYS я написал следующий код:Как создать триггер afterror в Oracle?

CREATE TABLE servererror_log (
    error_datetime TIMESTAMP, 
    error_user  VARCHAR2(30), 
    db_name   VARCHAR2(9), 
    error_stack  VARCHAR2(2000), 
    captured_sql VARCHAR2(1000)); 
/
CREATE OR REPLACE TRIGGER log_server_errors 
AFTER SERVERERROR 
ON DATABASE 
DECLARE 
captured_sql VARCHAR2(1000); 
BEGIN 
    SELECT q.sql_text 
    INTO captured_sql 
    FROM gv$sql q, gv$sql_cursor c, gv$session s 
    WHERE s.audsid = audsid 
    AND s.prev_sql_addr = q.address 
    AND q.address = c.parent_handle; 

    INSERT INTO servererror_log 
    (error_datetime, error_user, db_name, 
    error_stack, captured_sql) 
    VALUES 
    (systimestamp, sys.login_user, sys.database_name, 
    dbms_utility.format_error_stack, captured_sql); 
END log_server_errors; 

Но когда я заставить ошибку как пытаться выбрать из несуществующей таблицы он это не распространяется зарегистрировать ошибку в таблице.

Есть ли способ проверить, что срабатывает триггер? Кроме того, я попытался создать тестовую таблицу для ее вставки, но она тоже не работает, даже если определить триггер как автономную транзакцию и зафиксировать внутри триггера.

Спасибо, Joaquin

ответ

1

Не запрос v $ SQL; получить утверждение с помощью ora_sql_txt.

CREATE OR REPLACE TRIGGER log_server_errors 
AFTER SERVERERROR 
ON DATABASE 
DECLARE 
sql_text ora_name_list_t; 
stmt clob; 
n number; 
BEGIN 
    n := ora_sql_txt(sql_text); 
    if n > 1000 then n:= 1000; end if ; 
    FOR i IN 1..n LOOP 
    stmt := stmt || sql_text(i); 
    END LOOP; 

    INSERT INTO servererror_log 
    (error_datetime, error_user, db_name, 
    error_stack, captured_sql) 
    VALUES 
    (systimestamp, sys.login_user, sys.database_name, 
    dbms_utility.format_error_stack, stmt); 
    commit; 
END log_server_errors; 
/

Тогда:

SQL> select * from c; 

Это дает:

select * from c 
       * 
ERROR at line 1: 
ORA-00942: table or view does not exist 

То, что сейчас может быть запрошено:

select * from servererror_log; 

Для производства:

ERROR_DATETIME 
--------------------------------------------------------------------------- 
ERROR_USER      DB_NAME 
------------------------------ --------- 
ERROR_STACK 
-------------------------------------------------------------------------------- 
CAPTURED_SQL 
-------------------------------------------------------------------------------- 
11-FEB-09 02.55.35.591259 PM 
SYS       TS.WORLD 
ORA-00942: table or view does not exist 
select * from c 
+0

не работает. Также я пробовал этот же подход раньше, без каких-либо результатов. Кажется, что триггер не стреляет. Любые другие идеи? Вы знаете, как я могу проверить, был ли запущен триггер? Что-то вроде представления с столбцом LAST_FIRED_TIME или что-то в этом роде. Thanks Joaquin – xocasdashdash

+0

Может быть вставка. Проблема в том, что если триггер не работает, его трудно поймать. Я бы использовал UTL_FILE или отдельную процедуру с автономной транзакцией. См. http://stackoverflow.com/questions/492705/is-there-any-way-to-log-all-failed-sql-statements-in-oracle-10g –

0

Проверьте состояние вашего триггера и/или существование других триггеров с:

select trigger_name, status 
from all_triggers 
where triggering_event like 'ERROR%' 

Это должно привести к:

TRIGGER_NAME  STATUS 
------------  ------- 
LOG_SERVER_ERRORS ENABLED 

Если триггер не включен или другой триггер не удается, это, вероятно, не сработает.

1

Чтобы увидеть, если триггер стреляет, добавить одну или несколько строк в ней, как это:

DBMS_OUTPUT.PUT_LINE('Got this far'); 

В SQLPlus, SET SERVEROUTPUT ON затем выполнить команду, чтобы генерировать ошибку. Вы должны получить такой вывод:

dev> select * from aldfjh; 
select * from aldfjh 
       * 
ERROR at line 1: 
ORA-00942: table or view does not exist 


ORA-00942: table or view does not exist 

Got this far 
0

Сохранить как ORA-00942.sql:

-- Drop trigger and ignore errors (e.g., not exists). 
DECLARE 
    existential_crisis EXCEPTION; 
    PRAGMA EXCEPTION_INIT(existential_crisis, -4080); 
BEGIN 
    EXECUTE IMMEDIATE 'DROP TRIGGER TRG_CATCH_ERRORS /*+ IF EXISTS */'; 
    EXCEPTION WHEN existential_crisis THEN 
    DBMS_OUTPUT.PUT_LINE('Ignoring non-existence.'); 
END; 
/

-- Drop table and ignore errors (e.g., not exists). 
DECLARE 
    existential_crisis EXCEPTION; 
    PRAGMA EXCEPTION_INIT(existential_crisis, -942); 
BEGIN 
    EXECUTE IMMEDIATE 'DROP TABLE TBL_ERROR_LOG /*+ IF EXISTS */'; 
    EXCEPTION WHEN existential_crisis THEN 
    DBMS_OUTPUT.PUT_LINE('Ignoring non-existence.'); 
END; 
/

-- Create the table (will not exist due to drop statement). 
CREATE TABLE TBL_ERROR_LOG (
    occurred  timestamp, 
    account  varchar2(32), 
    database_name varchar2(32), 
    stack   clob, 
    query   clob 
); 

-- Create the trigger to log the errors. 
CREATE TRIGGER TRG_CATCH_ERRORS AFTER servererror ON database 
DECLARE 
    sql_text ora_name_list_t; 
    n   number; 
    query_  clob; 
BEGIN 
    n := ora_sql_txt(sql_text); 

    IF n > 1000 THEN n := 1000; END IF; 

    FOR i IN 1 .. n LOOP 
     query_ := query_ || sql_text(i); 
    END LOOP; 

    INSERT INTO TBL_ERROR_LOG 
     (occurred, account, database_name, stack, query) 
    VALUES 
     (systimestamp, sys.login_user, sys.database_name, 
    dbms_utility.format_error_stack, query_); 
END; 
/

Выполнить с помощью SQLPlus:

SQL> @ORA-00942.sql 
PL/SQL procedure successfully completed. 

PL/SQL procedure successfully completed. 

Table created. 

Trigger created. 

проверить:

select * from blargh; 
select * from TBL_ERROR_LOG; 

Выход:

2017-10-20 15:15:25.061 SCHEMA XE "ORA-00942: table or view does not exist" select * from blargh 
Смежные вопросы