вторник, 23 октября 2012 г.

Capture any failed SQL queries using database trigger in Oracle

Создаем таблицу куда будем записывать запросы с ошибками:
  1. CONNECT SYSTEM;
  2.  
  3. DROP TABLE servererror_log;
  4.  
  5. CREATE TABLE servererror_log (
  6. error_datetime TIMESTAMP,
  7. error_user VARCHAR2(30),
  8. db_name VARCHAR2(30),
  9. error_stack VARCHAR2(2000),
  10. call_stack VARCHAR2(2000),
  11. SID NUMBER,
  12. SQL_ID VARCHAR2 (13),
  13. sql_statement VARCHAR2(2000),
  14. sql_statement_all CLOB,
  15. CLIENT_INFO VARCHAR2(256 BYTE),
  16. CURR_SCHEMA VARCHAR2(256 BYTE),
  17. CURR_USER VARCHAR2(256 BYTE),
  18. CURR_DB_NAME VARCHAR2(256 BYTE),
  19. HOST VARCHAR2(256 BYTE),
  20. IP VARCHAR2(256 BYTE),
  21. OSUSER VARCHAR2(256 BYTE),
  22. SESSID VARCHAR2(256 BYTE),
  23. SESS_USER VARCHAR2(256 BYTE),
  24. TERMINAL VARCHAR2(256 BYTE)
  25. );
  26.  
  27. GRANT SELECT, INSERT, UPDATE, DELETE ON SYSTEM.SERVERERROR_LOG TO SCOTT;
Выдаем явный грант на V_$SESSION пользователю SYSTEM для того чтобы триггер log_server_errors указанный ниже скомпилировался.
  1. CONNECT SYS AS SYSDBA;
  2. GRANT SELECT ON V_$SESSION TO SYSTEM;
Триггер базы данных на SERVERERROR(в условии WHEN можем исключить ошибки которые не нужно логгировать, в данном примере - это ORA-25254):
  1. CONNECT SYSTEM;
  2.  
  3. DROP TRIGGER log_server_errors;
  4.  
  5. CREATE OR REPLACE TRIGGER log_server_errors
  6. AFTER SERVERERROR
  7. ON DATABASE WHEN (
  8. ORA_SERVER_ERROR(1)<>25254 /*ORA-25254: time-out in LISTEN while waiting for a message*/
  9. )
  10. DECLARE
  11. v_sql_statement VARCHAR2(32767);
  12. sql_text ora_name_list_t;
  13. n pls_integer;
  14. cursor c_user is
  15. select vs.sid sid,
  16. vs.sql_id sql_id,
  17. sys_context('USERENV','CLIENT_INFO') client_info,
  18. sys_context('USERENV','CURRENT_SCHEMA') curr_schema,
  19. sys_context('USERENV','CURRENT_USER') curr_user,
  20. sys_context('USERENV','DB_NAME') db_name,
  21. sys_context('USERENV','HOST') host,
  22. sys_context('USERENV','IP_ADDRESS') ip,
  23. sys_context('USERENV','OS_USER') osuser,
  24. sys_context('USERENV','SESSIONID') sessid,
  25. sys_context('USERENV','SESSION_USER') sess_user,
  26. sys_context('USERENV','TERMINAL') terminal
  27. from dual
  28. cross join v$session vs
  29. where 1 = 1
  30. and sys_context('USERENV','SESSIONID') = audsid
  31. ;
  32. user_rec c_user%rowtype;
  33. BEGIN
  34. open c_user;
  35. fetch c_user into user_rec;
  36. close c_user;
  37.  
  38. n := ora_sql_txt(sql_text);
  39. FOR i IN 1..n LOOP
  40. v_sql_statement := v_sql_statement || sql_text(i);
  41. END LOOP;
  42. INSERT INTO servererror_log(
  43. error_datetime, error_user, db_name,
  44. error_stack, call_stack,
  45. SID, SQL_ID,
  46. sql_statement, sql_statement_all,
  47. CLIENT_INFO, CURR_SCHEMA, CURR_USER, CURR_DB_NAME,
  48. HOST, IP, OSUSER, SESSID,
  49. SESS_USER, TERMINAL
  50. ) VALUES(
  51. systimestamp, sys.login_user, sys.database_name,
  52. ora_server_error_msg(1)/*dbms_utility.format_error_stack*/,
  53. dbms_utility.format_call_stack,
  54. user_rec.sid, user_rec.sql_id,
  55. substrb(v_sql_statement, 1, 2000),
  56. v_sql_statement,
  57. user_rec.client_info, user_rec.curr_schema, user_rec.curr_user,
  58. user_rec.db_name, user_rec.host, user_rec.ip,
  59. user_rec.osuser, user_rec.sessid, user_rec.sess_user,
  60. user_rec.terminal
  61. );
  62. --commit;
  63. END;
  64. /
Выбираем запросы с ошибками(см. поля SID, SQL_STATEMENT, SQL_STATEMENT_ALL):
  1. CONNECT SCOTT;
  2.  
  3. select * from system.servererror_log
  4. --where ERROR_USER = 'SCOTT'
  5. order by error_datetime desc
  6. ;
Дополнительные команды которые возможно пригодятся для трассировки сессии:
  1. CONNECT SYSTEM;
  2.  
  3. ALTER SYSTEM SET sql_trace = true SCOPE=MEMORY;
  4. ...
  5. select * from system.servererror_log;
  6. ...
  7.  
  8. ALTER SYSTEM SET sql_trace = false SCOPE=MEMORY;
  9.  
  10. --After Logon Trigger for Tracing on Schema:
  11. CONNECT SCOTT;
  12.  
  13. CREATE OR REPLACE TRIGGER SCOTT_AFTER_LOGON_TRG_00
  14. AFTER LOGON ON SCOTT.SCHEMA
  15. DECLARE
  16. sqlstr VARCHAR2(200) := 'ALTER SESSION SET EVENTS ''10046 TRACE NAME CONTEXT FOREVER, LEVEL 4''';
  17. BEGIN
  18. IF (USER = 'SCOTT') THEN
  19. execute immediate sqlstr;
  20. END IF;
  21. END;
  22. /