如果处理了异常(在PL/SQL中使用EXCEPTION处理),那么程序完全控制了对错误消息的处理,无论是记录它还是采取其他措施。客户可能永远看不到任何东西。开箱即用,Oracle不会记录错误(除非它们是核心错误-Oracle中的bug-如ORA-00600或ORA-07445,它们会立即终止您的流程;这些事件将在警报日志中,Oracle将创建特殊事件文件)。常规的编程异常不会出现在警报日志中。 然而,如果引发了一个异常,而这个异常一直到最外面的代码块都没有被处理,因此引发了一个异常到 * 客户端 *,那么是的,你可以在不修改代码的情况下记录这些异常,但是你必须在数据库/系统级别设置它。创建一个SERVERERROR ON DATABASE类型的系统触发器。以下是如何编写一个安全的日志,如果日志出现问题,它不会影响应用程序会话:
CREATE OR REPLACE TRIGGER SYSTEM.TR_SERVERERROR
AFTER SERVERERROR
ON DATABASE
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
IF ora_dict_obj_owner = SYS_CONTEXT('USERENV','CURRENT_SCHEMA') OR -- too dangerous, we could use components that are being modified and self-lock
SYS_CONTEXT('USERENV','SESSIONID') = 0 OR -- background processes
(SYS_CONTEXT('USERENV','SESSIONID') = 4294967295 AND (ora_dict_obj_owner = 'SYS' OR SYS_CONTEXT('USERENV','CLIENT_PROGRAM_NAME') NOT LIKE 'sqlplus%')) -- direct attached binaries, but allow sqlplus
THEN
NULL;
ELSE
EXECUTE IMMEDIATE 'BEGIN P_LOG_SERVER_ERROR; END;';
END IF;
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
/
server_error(1) -- error code, must reverse the sign
server_error_msg(1) -- error message
dbms_utility.format_error_stack -- full error stack
dbms_utility.format_error_backtrace -- backtrace
dbms_utility.format_call_stack -- call stack
utl_call_stack.concatenate_subprogram(utl_call_stack.subprogram(2)) -- erroring code unit
original_sql_txt(tab_sql) -- erroring SQL broken up into pieces, you have to reassemble
2条答案
按热度按时间yptwkmov1#
由开发人员来编写如何处理异常的代码。如果没有异常处理,则异常将按照文档中的描述进行传播。如果你想捕获在pl/sql代码(包/函数/过程/触发器)中引发的异常,那么你可以实现一个像logger这样的开源工具。请注意,这需要对所有pl/sql代码进行代码更改。没有异常处理被许多人视为bug。
juzqafwq2#
如果处理了异常(在PL/SQL中使用
EXCEPTION
处理),那么程序完全控制了对错误消息的处理,无论是记录它还是采取其他措施。客户可能永远看不到任何东西。开箱即用,Oracle不会记录错误(除非它们是核心错误-Oracle中的bug-如ORA-00600或ORA-07445,它们会立即终止您的流程;这些事件将在警报日志中,Oracle将创建特殊事件文件)。常规的编程异常不会出现在警报日志中。然而,如果引发了一个异常,而这个异常一直到最外面的代码块都没有被处理,因此引发了一个异常到 * 客户端 *,那么是的,你可以在不修改代码的情况下记录这些异常,但是你必须在数据库/系统级别设置它。创建一个
SERVERERROR ON DATABASE
类型的系统触发器。以下是如何编写一个安全的日志,如果日志出现问题,它不会影响应用程序会话:字符串
然后,您可以创建日志记录过程(这里是
P_LOG_SERVER_ERROR
),它使用各种变量和函数收集信息,其中一些变量和函数仅在系统触发器中可用:型
当然,可以从
SYS_CONTEXT('USERENV',....)
调用和查看v$session
、v$process
、v$session_connect_info
等获取有关会话的大量信息。然后将所需的信息插入到一个特殊的表中。然而,这种方法是为DBA准备的。为了创建这样的触发器,您需要
ADMINISTER DATABASE TRIGGER
权限,该权限太强大(而且很危险),不能给予非DBA。如果您不是DBA,但也不拥有要监视的代码,那么您可以与DBA讨论,让他们为您创建类似的东西。但是,如果您是有问题的代码的所有者,那么您应该在代码中编写适当的异常处理程序,并将触发器和数据库范围的日志记录留给DBA。