2012-04-19 212 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