programing

Oracle 패키지에 모든 예외를 기록하는 방법은 무엇입니까?

lastcode 2023. 8. 20. 11:13
반응형

Oracle 패키지에 모든 예외를 기록하는 방법은 무엇입니까?

모든 예외를 Oracle 패키지에 기록하려고 합니다.다음은 절차의 마지막 부분입니다.

EXCEPTION
   WHEN OTHERS THEN
      INSERT INTO VSLogger (MESSAGE) VALUES ('Caught Exception');

이것은 잘 작동하지만 오류 코드와 메시지도 기록하고 싶습니다.시도해 봤습니다.

EXCEPTION
   WHEN OTHERS THEN
      INSERT INTO VSLogger (MESSAGE) VALUES ('Caught Exception: Error ' || SQLCODE || ', Msg: ' || SQLERRM);

하지만 이것은 나에게 오류를 줍니다.

490/7    PL/SQL: SQL Statement ignored
490/100  PL/SQL: ORA-00984: column not allowed here

이것을 하는 올바른 방법은 무엇입니까?감사합니다!

사용 안 함SQLERRM또는SQLCODE라인 번호를 저장하지 않고 예외를 기록하는 것은 잔인합니다.

항상 사용dbms_utility.format_error_stack||dbms_utility.format_error_backtrace아니면 비슷한 것.

예를 들어 다음 블록에는 오류가 표시되지만 발생한 위치는 표시되지 않습니다.

declare
    v_number number;
begin
    v_number := 1/0;
exception when others then
    dbms_output.put_line(sqlerrm);
end;
/

DBMS Output:
ORA-01476: divisor is equal to zero

이 블록에는 오류와 발생한 위치가 모두 표시됩니다.중요하지 않은 프로그램의 문제를 해결하는 데 중요한 정보입니다.

declare
    v_number number;
begin
    v_number := 1/0;
exception when others then
    dbms_output.put_line(dbms_utility.format_error_stack||dbms_utility.format_error_backtrace);
end;
/

DBMS Output:
ORA-01476: divisor is equal to zero
ORA-06512: at line 4

(아래는 몇 가지 일반적인 예외 처리 권장 사항입니다.)

실제 코드의 경우 오류 정보를 단순히 출력하지 않습니다.실제로 가장 좋은 예외 처리 전략은 일반적으로 아무것도 하지 않고 Oracle의 기본 동작을 사용하여 모든 오류 메시지와 줄 번호를 표시하는 것입니다.

Oracle의 사용자 지정 예외 처리는 일반적으로 다음 세 가지 경우 중 하나에서만 유용합니다.

  1. 오류를 무시하는 다른 절차를 호출하는 등 특정 오류가 있는 작업을 수행합니다.
  2. 데이터베이스 전용 프로그램인 경우 프로그램 상단(제한된 수의 진입점)에서 예외를 포착하고 기록할 수 있습니다.응용 프로그램이 이미 모든 것을 인식하거나 내부 코드에 대해 예외 처리를 수행할 필요가 없습니다.예외는 스택 위로 전파되므로 마지막에 잡는 것이 가장 좋습니다.
  3. 로컬 변수로만 존재하는 특정 값을 기록해야 하는 경우 해당 값이 예외와 함께 전파되지 않으므로 즉시 기록해야 합니다.

모든 절차에서 오류를 맹목적으로 포착하고 기록하는 PL/SQL 코드가 많습니다.그것은 불필요하고 일반적으로 역효과를 낳습니다.

사용할 수 없습니다.SQLERRM직접 - 중간 변수에 할당해야 합니다.Oracle 9i를 사용하면 문제를 해결할 수 있지만 항상 문서화된 동작입니다.샘플 코드는 여기를 참조하십시오.

PL/SQL 코드의 트랜잭션이 롤백되더라도 기록되도록 이 비트를 자동 트랜잭션으로 래핑하는 것도 고려할 수 있습니다.

가이우스가 당신에게 짧은 대답을 했습니다.그것을 자율적인 거래로 포장하는 것에 대한 그의 의견은 매우 중요합니다.당신은 당신의 거래가 철회된 날을 후회하게 될 것이고, 왜 그런지는 모릅니다.

여기에 오류가 발생한 위치에 대해 더 자세히 알 수 있도록 몇 가지 추가 세부 정보가 포함된 자율 트랜잭션을 사용하는 방법이 나와 있습니다.

예외 블록은 다음과 같이 됩니다.

exception
   when exception_pkg.assertion_failure_exception then
      rollback;
      raise;
   when others then 
      rollback;
      v_code := SQLCODE;
      v_errm := SUBSTR(SQLERRM, 1, 255);
      exception_pkg.throw( exception_pkg.unhandled_except, v_code || ' - ' || v_errm || ' ($Header$)' );

aaa and, 여기 이것을 지원하는 데 필요한 모든 코드가 있습니다.가지고 놀아요, 유용해요 :-)

-- Create a table to hold the error messages

CREATE TABLE ERROR_MESSAGES
(
  ERROR_MESSAGE_ID   NUMBER(10)                 NOT NULL,
  ERROR_DATE         TIMESTAMP(6)               DEFAULT SYSDATE               NOT NULL,
  ERROR_USER         VARCHAR2(30 BYTE)          DEFAULT USER                  NOT NULL,
  MESSAGE_TYPE       VARCHAR2(15 BYTE),
  PACKAGE_NAME       VARCHAR2(250 BYTE),
  PROCEDURE_OR_LINE  VARCHAR2(30 BYTE),
  ERROR_CODE         VARCHAR2(10 BYTE),
  ERROR_MESSAGE1     VARCHAR2(4000 BYTE),
  ERROR_MESSAGE2     VARCHAR2(4000 BYTE),
  ERROR_MESSAGE3     VARCHAR2(4000 BYTE),
  ERROR_MESSAGE4     VARCHAR2(4000 BYTE)
);


CREATE UNIQUE INDEX ERROR_MESSAGES_XPK ON ERROR_MESSAGES
(ERROR_MESSAGE_ID);

-- Create the sequence used for the ERROR_MESSAGES PK

CREATE SEQUENCE ERROR_MESSAGE_SEQ
  START WITH 1;

-- The package

CREATE OR REPLACE PACKAGE EXCEPTION_PKG 
as

   /************************************************************************************
   * $Header$
   *
   * Package: exception_pkg
   *
   * Purpose: Exception handling functionality
   *
   * Authors: M.McAllister (via AskTom - http://tinyurl.com/c43jt)
   *
   * Revision History:
   *
   * $Log[10]$
   ******************************************************************************************/

   /*=====================================================================
   * Constants
   *=====================================================================*/

   c_InfMsg    constant error_messages.message_type%type := 'Informational';
   c_WarnMsg   constant error_messages.message_type%type := 'Warning';
   c_ErrMsg    constant error_messages.message_type%type := 'Fatal Error';
   c_DbgMsg    constant error_messages.message_type%type := 'Debug';
   c_MaintMsg  constant error_messages.message_type%type := 'Maintenance';

   /*=====================================================================
   * Exception Definitions
   *=====================================================================*/

   unhandled_except              constant number := -20001;
   unhandled_except_exception    exception;
   pragma exception_init(unhandled_except_exception, -20001);

   bad_parameter                 constant number := -20002;
   bad_parameter_exception       exception;
   pragma exception_init(bad_parameter_exception, -20002);

   assertion_failure             constant number := -20003;
   assertion_failure_exception   exception;
   pragma exception_init(assertion_failure_exception, -20003);

   /*=====================================================================
   * Procedures
   *=====================================================================*/

   procedure write_exception_info( p_msg_type   error_messages.message_type%type
                                 , p_pkg_name   error_messages.package_name%type
                                 , p_func_name  error_messages.procedure_or_line%type
                                 , p_error_code error_messages.error_code%type
                                 , p_msg1       error_messages.error_message2%type
                                 , p_msg2       error_messages.error_message3%type
                                 , p_msg3       error_messages.error_message4%type
                                 );

   procedure who_called_me( p_owner      out varchar2,
                            p_name       out varchar2,
                            p_lineno     out number,
                            p_caller_t   out varchar2,
                            p_my_depth   in number default 3
                          );

   procedure throw( p_exception in number
                  , p_extra_msg in varchar2 default NULL
                  );

end exception_pkg;
/

-- Package Body

CREATE OR REPLACE PACKAGE BODY EXCEPTION_PKG 
as

   /************************************************************************************
   * $Header$
   *
   * Package: exception_pkg
   *
   * Purpose: Exception handling functionality
   *
   * Authors: M.McAllister (via AskTom - http://tinyurl.com/c43jt)
   *
   * Revision History:
   *
   * $Log[10]$
   ******************************************************************************************/

   /*=====================================================================
   * Types
   *=====================================================================*/

   type myArray is table of varchar2(255) index by binary_integer;

   /*=====================================================================
   * Globals
   *=====================================================================*/

   err_msgs  myArray;

   /*=====================================================================
   * Procedures
   *=====================================================================*/

   procedure who_called_me( p_owner      out varchar2,
                            p_name       out varchar2,
                            p_lineno     out number,
                            p_caller_t   out varchar2,
                            p_my_depth   in number default 3
                          )
   as
       call_stack  varchar2(4096) default dbms_utility.format_call_stack;
       n           number;
       found_stack BOOLEAN default FALSE;
       line        varchar2(255);
       cnt         number := 0;
   begin

       loop
           n := instr( call_stack, chr(10) );
           exit when ( cnt = p_my_depth or n is NULL or n = 0 );

           line := substr( call_stack, 1, n-1 );
           call_stack := substr( call_stack, n+1 );

           if ( NOT found_stack ) then
               if ( line like '%handle%number%name%' ) then
                   found_stack := TRUE;
               end if;
           else
               cnt := cnt + 1;
               -- cnt = 1 is ME
               -- cnt = 2 is MY Caller
               -- cnt = 3 is Their Caller
               if ( cnt = p_my_depth ) then
                   p_lineno := to_number(substr( line, 13, 6 ));
                   line   := substr( line, 21 );
                   if ( line like 'pr%' ) then
                       n := length( 'procedure ' );
                   elsif ( line like 'fun%' ) then
                       n := length( 'function ' );
                   elsif ( line like 'package body%' ) then
                       n := length( 'package body ' );
                   elsif ( line like 'pack%' ) then
                       n := length( 'package ' );
                   elsif ( line like 'anonymous%' ) then
                       n := length( 'anonymous block ' );
                   else
                       n := null;
                   end if;
                   if ( n is not null ) then
                      p_caller_t := ltrim(rtrim(upper(substr( line, 1, n-1 ))));
                   else
                      p_caller_t := 'TRIGGER';
                   end if;

                   line := substr( line, nvl(n,1) );
                   n := instr( line, '.' );
                   p_owner := ltrim(rtrim(substr( line, 1, n-1 )));
                   p_name  := ltrim(rtrim(substr( line, n+1 )));
               end if;
           end if;
       end loop;

   end who_called_me;

   /*=====================================================================
   * PRIVATE function: get_session_info
   * purpose:   Returns a formatted string containing some information
   *            about the current session
   *=====================================================================*/

   function get_session_info return varchar2 is

      l_sessinfo     varchar2(2000);

   begin

      select
         '[SID = ' || sid || '], ' ||
         '[SERIAL# = ' || serial# ||'], ' ||
         '[MACHINE = ' || replace(machine,chr(0),'') || '], ' ||
         '[OSUSER = ' || osuser || '], ' ||
         '[PROGRAM = ' || program || '], ' ||
         '[LOGON_TIME = ' || to_char(logon_time,'mm/dd/yyyy hh:mi:ss') || ']' into l_sessinfo
      from v$session
      WHERE audsid = SYS_CONTEXT('userenv','sessionid');

      return l_sessinfo;

   end get_session_info;

   /*=====================================================================
   * procedure: write_exception_info
   * purpose:   Call the exception logging routine
   *=====================================================================*/

   procedure write_exception_info( p_msg_type   error_messages.message_type%type
                                 , p_pkg_name   error_messages.package_name%type
                                 , p_func_name  error_messages.procedure_or_line%type
                                 , p_error_code error_messages.error_code%type
                                 , p_msg1       error_messages.error_message2%type
                                 , p_msg2       error_messages.error_message3%type
                                 , p_msg3       error_messages.error_message4%type
                                 ) is

   -- This procedure is autonomous from the calling procedure.
   -- i.e The calling procedure does not have to be complete
   -- for this procedure to commit its changes.
   pragma autonomous_transaction;
   l_sessinfo     varchar2(2000);

   begin

      l_sessinfo := get_session_info;

      insert into error_messages
         ( error_message_id
         , error_date
         , error_user
         , message_type
         , package_name
         , procedure_or_line
         , error_code
         , error_message1
         , error_message2
         , error_message3
         , error_message4
         )
      values
         ( error_message_seq.nextval
         , sysdate
         , USER
         , p_msg_type
         , p_pkg_name
         , p_func_name
         , p_error_code
         , l_sessinfo
         , p_msg1
         , p_msg2
         , p_msg3
         );

      commit;

   exception
      when others then
         -- We don't want an error logging a message to
         -- cause the application to crash
         return;

   end write_exception_info;

   procedure throw( p_exception in number
                  , p_extra_msg in varchar2 default NULL
                  ) is

      l_owner        varchar2(30);
      l_name         varchar2(30);
      l_type         varchar2(30);
      l_line         number;
      l_exception    number;

   begin

     who_called_me( l_owner, l_name, l_line, l_type );
     write_exception_info( c_ErrMsg
                         , l_owner || '.' || l_name
                         , 'Line ' || l_line
                         , p_exception
                         , p_extra_msg
                         , NULL
                         , err_msgs(p_exception)
                         );
     raise_application_error( p_exception
                            , 'Exception at ' || l_type || ' ' ||
                              l_owner || '.' || l_name || '(' || l_line || '). ' ||
                              err_msgs(p_exception       ) || '. ' || p_extra_msg
                            , TRUE );

   exception
      -- we will get this when we have an invalid exception code, one
      -- that was not set in the err_msgs array below.  The plsql table
      -- access will raise the NO-DATA-FOUND exception.  We'll catch it,
      -- verify the exception code is in the valid range for raise_application_error
      -- (if not, set to -20000) and then raise the exception with the message
      -- "unknown error"

     when NO_DATA_FOUND then
         if ( p_exception between -20000 and -20999 ) then
            l_exception := p_exception;
         else
            l_exception := -20000;
         end if;

        write_exception_info( c_ErrMsg
                            , l_owner || '.' || l_name
                            , 'Line ' || l_line
                            , p_exception
                            , p_extra_msg
                            , NULL
                            , '**UNKNOWN ERROR**'
                            );
         raise_application_error( l_exception
                                , 'Exception at ' || l_type || ' ' ||
                                  l_owner || '.' || l_name || '(' || l_line || '). ' ||
                                  '**UNKNOWN ERROR**' || '. ' || p_extra_msg
                                , TRUE );

   end throw;

begin

   -- This code is run once per session when this package is first touched

   err_msgs( unhandled_except ) := 'Unhandled exception';
   err_msgs( bad_parameter ) := 'Invalid parameter passed into function or procedure';
   err_msgs( assertion_failure ) := 'Program execution stopped due to assertion failure';

end exception_pkg;
/

언급URL : https://stackoverflow.com/questions/9184865/how-to-log-all-exceptions-in-oracle-package

반응형