2012-04-19 56 views
2

我写在Oracle 10g中一个记录的过程,它写入一个表具有以下插入调用包/程序:获取甲骨文

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

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

我想知道是否有一个v $视图或Oracle中的哪些东西可以告诉我该程序是从哪个包中调用的,因此不需要程序员通过strPackagestrProcedure

例:

如果我调用这两个过程:

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从insdie write_exec_log方法。

回答

1
+1

这将让我的包名称,而不是程序名称。我为这个问题增加了一个例子。调用堆栈包含'log_test',但不包含'TestProc1'。 – Paul 2012-04-19 15:40:59

+0

您可以从包中获取行号。这足够接近了吗? – 2012-04-19 15:49:49

+0

并不是真的,我也想用它来表现指标,所以我想知道当调用write_exec_log时什么程序正在运行。 – Paul 2012-04-19 15:57:01

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)

0

Here是针对Oracle 9的utl_call_stack的实现(backport)。以及针对Oracle 10 and 11

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

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

随着GWu's example,它会输出:

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 

它适用于Oracle版本9至12