2009-02-11 14 views
5

Estoy tratando de registrar todos los errores en mi base de datos en una tabla. Así como usuario sys i escribió el siguiente código:¿Cómo desarrollar un desencadenador after serverror en 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; 

Pero cuando fuerzo un error como tratar de seleccionar de una tabla no existente que Indiferente registrar el error en la tabla.

¿Hay alguna manera de verificar que el gatillo se dispare en absoluto? Además, intenté crear una tabla de prueba para insertar allí, pero tampoco funciona, incluso si defino el activador como una transacción autónoma y me comprometo dentro del desencadenador.

Gracias, Joaquín

Respuesta

1

no efectuar petición v $ sql; obtener la declaración 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; 
/

continuación:

SQL> select * from c; 

Esto produce:

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

Que ahora se pueden consultar:

select * from servererror_log; 

Para producir:

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

no funciona. También he intentado este mismo enfoque antes sin resultados. Parece que el gatillo no está disparando. ¿Alguna otra idea? ¿Sabes cómo puedo verificar si se disparó un disparador? Algo así como una vista con una columna LAST_FIRED_TIME o algo así. Gracias Joaquin – xocasdashdash

+0

Podría ser el inserto. El problema es que si falla el gatillo, es difícil de atrapar. Yo usaría UTL_FILE o un procedimiento separado con transacción autónoma. Ver http://stackoverflow.com/questions/492705/is-there-any-way-to-log-all-failed-sql-statements-in-oracle-10g –

0

Comprobar el estado de su gatillo y/o la existencia de otros factores desencadenantes con:

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

Esto debería resultar en:

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

Si el gatillo no está activado o no otro factor desencadenante, probablemente no funcionará.

1

para ver si el gatillo está disparando, añadir una o más líneas de esta manera:

DBMS_OUTPUT.PUT_LINE('Got this far'); 

En SQLPlus, SET serveroutput EN luego ejecutar un comando para generar un error. Usted debe obtener una salida como ésta:

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

Guardar esto como 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; 
/

Ejecutar utilizando sqlplus:

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

PL/SQL procedure successfully completed. 

Table created. 

Trigger created. 

prueba que:

select * from blargh; 
select * from TBL_ERROR_LOG; 

Salida:

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