2009-02-11 15 views
5

Sto provando a registrare tutti gli errori nel mio database in una tabella. Così come utente SYS ho scritto il seguente codice:Come sviluppare un trigger after serverror in 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; 

Ma quando forzo un errore come cercando di selezionare da una tabella inesistente che accedo Indifferente l'errore nella tabella.

C'è un modo per controllare che il trigger si attiva? Inoltre, ho provato a creare una tabella di test da inserire lì ma non funziona neanche, anche se definisci il trigger come una transazione autonoma e commetti all'interno del trigger.

Grazie, Joaquin

risposta

1

Non interrogare v $ sql; ottieni la dichiarazione usando 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; 
/

Poi:

SQL> select * from c; 

Questo produce:

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

che possono ora essere interrogato:

select * from servererror_log; 

produrre:

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

non funziona. Inoltre ho provato questo stesso approccio prima senza risultati. Sembra che l'innesco non stia sparando. Altre idee? Sai come posso verificare se è stato attivato un trigger? Qualcosa come una vista con una colonna LAST_FIRED_TIME o qualcosa del genere. Grazie Joaquin – xocasdashdash

+0

Potrebbe essere l'inserto. Il problema è che se il trigger fallisce, è difficile da catturare. Avrei usato UTL_FILE o una procedura separata con una transazione autonoma. Vedi http://stackoverflow.com/questions/492705/is-there-any-way-to-log-all-failed-sql-statements-in-oracle-10g –

0

Controllare lo stato del tuo grilletto e/o l'esistenza di altri trigger con:

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

Questo dovrebbe risultare in:

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

Se grilletto non è abilitato o un altro trigger non riesce, probabilmente non funzionerà.

1

per vedere se il grilletto è sparare, aggiungere una o più linee ad esso in questo modo:

DBMS_OUTPUT.PUT_LINE('Got this far'); 

In SQLPlus, SET SERVEROUTPUT ON quindi eseguire un comando per generare un errore. Si dovrebbe ottenere un output simile a questo:

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

Salva questo come 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; 
/

Run utilizzando sqlplus:

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

PL/SQL procedure successfully completed. 

Table created. 

Trigger created. 

prova è:

select * from blargh; 
select * from TBL_ERROR_LOG; 

Uscita:

2017-10-20 15:15:25.061 SCHEMA XE "ORA-00942: table or view does not exist" select * from blargh