2

我在 Oracle 10g 中编写了一个日志记录过程,它使用以下插入写入表:

INSERT INTO EXEC_LOG VALUES (
  (SELECT SYS_CONTEXT('USERENV','SESSIONID') sessionid FROM dual),
  strPackage, strProcedure, strEventType, strEventLevel, SYSDATE, strMessage
);

这个过程在多个不同的包/过程中重复使用,但是现在的方式是,程序员必须将他们的包/过程名称传递给日志记录过程(strPackagestrProcedure)。

我想知道 Oracle 中是否有 av$ 视图或其他东西可以告诉我这个过程是从哪个包/过程中调用的,从而消除了程序员传入strPackageand的需要strProcedure

例子:

如果我调用这两个程序:

BEGIN
  log_test.testproc1;
  log_test.testproc2;
END;

从这个包:

CREATE OR REPLACE PACKAGE BODY log_test IS
  PROCEDURE TestProc1 IS
    BEGIN
      write_exec_log( ... );    
    END TestProc1;
  PROCEDURE TestProc2 IS
    BEGIN
      write_exec_log( ... );     
    END TestProc2;  
 END log_test; 

我希望能够评估log_test/TestProc1log_test/TestProc2从 insdiewrite_exec_log方法。

4

3 回答 3

3

从 Oracle 12c 开始,您可以使用内置包 UTL_CALL_STACK ( http://docs.oracle.com/database/121/ARPLS/u_call_stack.htm )。

如果您只对调用过程感兴趣,则简短示例: DBMS_OUTPUT.PUT_LINE(UTL_Call_Stack.Concatenate_Subprogram(UTL_Call_Stack.Subprogram(2)));

或者打印完整的调用堆栈:

FOR j IN REVERSE 1..UTL_Call_Stack.Dynamic_Depth() LOOP 
  DBMS_OUTPUT.PUT_LINE(UTL_Call_Stack.Concatenate_Subprogram(UTL_Call_Stack.Subprogram(j)));
END LOOP;

您的包裹示例:

CREATE OR REPLACE PACKAGE  log_test IS
 PROCEDURE write_exec_log(msg VARCHAR2);
 PROCEDURE TestProc1;
 PROCEDURE TestProc2;  
 PROCEDURE TestProc3;
END log_test; 
/

CREATE OR REPLACE PACKAGE BODY log_test IS
 PROCEDURE write_exec_log(msg VARCHAR2) IS
  BEGIN
   DBMS_OUTPUT.PUT_LINE(msg);
   DBMS_OUTPUT.PUT_LINE('-- ');
   DBMS_OUTPUT.PUT_LINE('calling procedure/function: '
                      ||UTL_Call_Stack.Concatenate_Subprogram(
                                                              UTL_Call_Stack.Subprogram(2)
                                                             )
                       );
   DBMS_OUTPUT.PUT_LINE('-- ');
   DBMS_OUTPUT.PUT_LINE('Call Stack');
   FOR j IN REVERSE 1..UTL_Call_Stack.Dynamic_Depth() LOOP
    DBMS_OUTPUT.PUT_LINE(UTL_Call_Stack.Concatenate_Subprogram(
                                                               UTL_Call_Stack.Subprogram(j)
                                                              )
                        );
   END LOOP;
  END write_exec_log;
 PROCEDURE TestProc1 IS
  BEGIN
   write_exec_log( 'msg TestProc1' );    
  END TestProc1;
 PROCEDURE TestProc2 IS
  BEGIN
   write_exec_log( 'msg TestProc2' );     
  END TestProc2;  
 PROCEDURE TestProc3 IS
  BEGIN
   TestProc2;
  END TestProc3;  
END log_test; 
/

exec log_test.TestProc1
exec log_test.TestProc2
exec log_test.TestProc3

(抱歉,在撰写本文时没有 sqlfiddle,没有可用的 12c)

于 2015-07-16T12:52:37.390 回答
1

Tom Kyte 的 Who_Called_Me 应该可以工作。

于 2012-04-19T14:51:56.323 回答
0

utl_call_stackOracle 9 和 Oracle 10 和 11的实现(反向移植) 。

另一种解决方案(使用p_stack包):

dbms_output.put_line( p_stack.getConcatenatedSubprograms( p_stack.whoCalledMe ) );

使用GWu 的示例,它将输出:

LOG_TEST.TESTPROC1
LOG_TEST.TESTPROC2
LOG_TEST.TESTPROC2

这些只是最后的电话。或者,如果您需要完整的堆栈:

dbms_output.put_line( p_stack.getCallStack );
dbms_output.put_line( '' );

这将输出:

493: YOUR_SCHEMA.PACKAGE BODY P_STACK.FUNCTION GETCALLSTACK.FUNCTION GETCALLSTACK
4: YOUR_SCHEMA.PACKAGE BODY LOG_TEST.PROCEDURE WRITE_EXEC_LOG
9: YOUR_SCHEMA.PACKAGE BODY LOG_TEST.PROCEDURE TESTPROC1
2: YOUR_SCHEMA.ANONYMOUS BLOCK

493: YOUR_SCHEMA.PACKAGE BODY P_STACK.FUNCTION GETCALLSTACK.FUNCTION GETCALLSTACK
4: YOUR_SCHEMA.PACKAGE BODY LOG_TEST.PROCEDURE WRITE_EXEC_LOG
13: YOUR_SCHEMA.PACKAGE BODY LOG_TEST.PROCEDURE TESTPROC2
3: YOUR_SCHEMA.ANONYMOUS BLOCK

493: YOUR_SCHEMA.PACKAGE BODY P_STACK.FUNCTION GETCALLSTACK.FUNCTION GETCALLSTACK
4: YOUR_SCHEMA.PACKAGE BODY LOG_TEST.PROCEDURE WRITE_EXEC_LOG
13: YOUR_SCHEMA.PACKAGE BODY LOG_TEST.PROCEDURE TESTPROC2
17: YOUR_SCHEMA.PACKAGE BODY LOG_TEST.PROCEDURE TESTPROC3
4: YOUR_SCHEMA.ANONYMOUS BLOCK

它适用于从 9 到 12 的 Oracle 版本。

于 2015-12-10T12:33:59.520 回答