728x90

오라클에서 DBMS_OUTPUT.PUT_LINE의 출력을 테이블에 저장하면서, 단순히 메시지뿐만 아니라 호출된 프로시저명과 라인 번호를 함께 기록하고 싶다면, PL/SQL의 내장 기능을 활용해 호출 스택을 분석해야 합니다. 이를 위해 DBMS_UTILITY.FORMAT_CALL_STACK을 사용하면 호출 경로와 라인 번호를 추출할 수 있습니다. 아래에서 이를 구현하는 방법을 단계별로 정리하겠습니다.
목표
-
DBMS_OUTPUT.PUT_LINE 대신 커스텀 프로시저를 사용해 디버깅 메시지를 테이블에 저장.
-
메시지와 함께 호출된 프로시저명, 라인 번호를 기록.
-
실시간 디버깅과 영구 로그를 모두 지원.
728x90
1. 로그 테이블 생성
먼저, 메시지뿐만 아니라 프로시저명과 라인 번호를 저장할 수 있도록 테이블을 설계합니다.
CREATE TABLE debug_log (
log_id NUMBER GENERATED ALWAYS AS IDENTITY,
log_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
procedure_name VARCHAR2(100),
line_number NUMBER,
message VARCHAR2(4000)
);
2. 커스텀 디버깅 프로시저 작성
DBMS_UTILITY.FORMAT_CALL_STACK을 활용해 호출 스택에서 프로시저명과 라인 번호를 추출하고, 이를 테이블에 삽입하는 프로시저를 작성합니다.
CREATE OR REPLACE PROCEDURE custom_put_line(p_message IN VARCHAR2)
AS
l_call_stack VARCHAR2(4000);
l_lines DBMS_UTILITY.NAME_ARRAY;
l_line_count NUMBER;
l_procedure_name VARCHAR2(100);
l_line_number NUMBER;
BEGIN
-- 호출 스택 가져오기
l_call_stack := DBMS_UTILITY.FORMAT_CALL_STACK;
-- 호출 스택을 줄 단위로 분리
l_line_count := REGEXP_COUNT(l_call_stack, CHR(10));
FOR i IN 1..l_line_count LOOP
l_lines(i) := REGEXP_SUBSTR(l_call_stack, '[^\n]+', 1, i);
END LOOP;
-- 호출한 프로시저명과 라인 번호 추출 (최근 호출자 정보는 상위 몇 줄에 있음)
FOR i IN 1..l_line_count LOOP
IF REGEXP_LIKE(l_lines(i), 'procedure|function|anonymous') THEN
l_procedure_name := REGEXP_SUBSTR(l_lines(i), '[^. ]+$'); -- 마지막 단어 (프로시저명)
l_line_number := TO_NUMBER(REGEXP_SUBSTR(l_lines(i-1), '\d+')); -- 이전 줄의 라인 번호
EXIT;
END IF;
END LOOP;
-- 테이블에 삽입
INSERT INTO debug_log (procedure_name, line_number, message)
VALUES (l_procedure_name, l_line_number, p_message);
COMMIT; -- 필요에 따라 제거 가능
-- 콘솔에도 출력
DBMS_OUTPUT.PUT_LINE(p_message || ' (from ' || l_procedure_name || ' at line ' || l_line_number || ')');
EXCEPTION
WHEN OTHERS THEN
INSERT INTO debug_log (procedure_name, line_number, message)
VALUES ('ERROR_HANDLER', 0, 'Error in custom_put_line: ' || SQLERRM);
COMMIT;
RAISE;
END custom_put_line;
/
3. 사용 예제
작성한 custom_put_line을 호출해 테스트합니다.
CREATE OR REPLACE PROCEDURE test_debug
AS
BEGIN
custom_put_line('This is a test message');
END test_debug;
/
BEGIN
test_debug;
END;
/
-- 결과 확인
SELECT * FROM debug_log;
예상 출력 (debug_log 테이블):
LOG_ID LOG_TIME PROCEDURE_NAME LINE_NUMBER MESSAGE
1 2025-03-17 10:00:00 test_debug 4 This is a test message
콘솔 출력:
This is a test message (from test_debug at line 4)
4. 코드 설명
-
DBMS_UTILITY.FORMAT_CALL_STACK: 호출 스택을 문자열로 반환합니다. 예:
----- PL/SQL Call Stack ----- object line object handle number name 0x12345678 3 anonymous block 0xabcdef12 4 procedure TEST_DEBUG
-
정규 표현식: REGEXP_SUBSTR와 REGEXP_LIKE를 사용해 스택에서 프로시저명과 라인 번호를 추출.
-
테이블 삽입: INSERT INTO debug_log로 모든 정보를 기록.
-
예외 처리: 오류 발생 시에도 로그를 남김.
5. 주의사항
-
성능: 호출 스택 파싱은 약간의 오버헤드가 있으므로, 대량 호출 시 성능 테스트 필요.
-
정확성: 스택의 구조는 환경에 따라 다를 수 있으니, 추출 로직을 조정해야 할 수도 있음.
-
대체 방법: 더 정확한 라인 번호를 위해 $$PLSQL_LINE (현재 라인 번호)과 $$PLSQL_UNIT (현재 유닛 이름)을 사용할 수도 있음:
INSERT INTO debug_log (procedure_name, line_number, message) VALUES ($$PLSQL_UNIT, $$PLSQL_LINE, p_message);
하지만 이는 호출자의 정보가 아닌 현재 프로시저의 정보만 제공합니다.
6. 확장 가능성
-
추가 정보: 세션 ID(SYS_CONTEXT('USERENV', 'SESSIONID'))나 사용자명(USER)을 추가.
-
로그 레벨: 메시지에 레벨(예: INFO, ERROR)을 추가해 필터링 가능.
728x90
'Oracle Database 강좌' 카테고리의 다른 글
오라클에서 윈도우 로그인 시 사용자 이름 알아내는 방법 (0) | 2025.03.17 |
---|---|
실무에서 유용한 Oracle 샘플 테이블과 MERGE INTO 활용 예제 (0) | 2025.03.07 |
로컬 Oracle 데이터베이스와 리모트 Oracle 데이터베이스 연결 설정 가이드 (DB 링크 생성) (0) | 2025.02.13 |
오라클 대용량 테이블 성능 향상: 테이블 파티셔닝 재정의를 통한 최적화 (1) | 2024.12.21 |
오라클 데이터베이스와 웹훅(Webhook) 통합: PL/SQL과 JSON_OBJECT_T를 활용한 실전 가이드 (1) | 2024.12.16 |