문제

로깅 목적으로 예외를 잡아야 합니까?

public foo(..)
{
   try
   {
     ...
   } catch (Exception ex) {
     Logger.Error(ex);
     throw;
   }
}

각 레이어(DataAccess, Business 및 WebService)에 이 기능이 있으면 예외가 여러 번 기록된다는 의미입니다.

내 레이어가 별도의 프로젝트에 있고 공개 인터페이스에만 try/catch가 있는 경우 그렇게 하는 것이 합리적입니까?왜?왜 안 돼?사용할 수 있는 다른 접근 방식이 있나요?

도움이 되었습니까?

해결책

기필코 아니다.정확한 위치를 찾아야 합니다 핸들 예외를 처리하고(실제로 catch하고 다시 던지지 않는 등의 작업 수행) 이를 기록합니다.물론 전체 스택 추적을 포함할 수 있고 포함해야 하지만 제안을 따르면 코드가 try-catch 블록으로 가득 차게 됩니다.

다른 팁

예외를 변경하지 않는 한, 오류를 처리할 수준에서만 기록하고 오류를 다시 발생시키지 않아야 합니다.그렇지 않으면 로그에는 각 레이어에 한 번씩 3개 이상의 동일한 메시지가 기록되는 "노이즈"가 잔뜩 있을 뿐입니다.

내 모범 사례는 다음과 같습니다.

  1. 공개 메서드에서만 try/catch(일반적으로;분명히 특정 오류를 트래핑하는 경우 거기에서 확인해야 합니다)
  2. 오류를 억제하고 오류 페이지/양식으로 리디렉션하기 직전에 UI 레이어에만 로그인하세요.

일반적인 경험 법칙은 실제로 예외에 대해 조치를 취할 수 있는 경우에만 예외를 포착한다는 것입니다.따라서 비즈니스 또는 데이터 계층에서는 다음과 같은 상황에서만 예외를 포착합니다.

            try
            {
                this.Persist(trans);
            }
            catch(Exception ex)
            {
                trans.Rollback();
                throw ex;
            }

내 비즈니스/데이터 계층은 데이터 저장을 시도합니다. 예외가 생성되면 모든 트랜잭션이 롤백되고 예외가 UI 계층으로 전송됩니다.

UI 계층에서 일반적인 예외 처리기를 구현할 수 있습니다.

Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);

그런 다음 모든 예외를 처리합니다.예외를 기록한 다음 사용자에게 친숙한 응답을 표시할 수 있습니다.

    static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
    {
        LogException(e.Exception);
    }
    static void LogException(Exception ex)
    {
        YYYExceptionHandling.HandleException(ex,
            YYYExceptionHandling.ExceptionPolicyType.YYY_Policy,
            YYYExceptionHandling.ExceptionPriority.Medium,
            "An error has occurred, please contact Administrator");
    } 

실제 UI 코드에서는 다른 친숙한 메시지를 표시하거나 화면을 수정하는 등 다른 작업을 수행하려는 경우 개별 예외를 포착할 수 있습니다.

또한, 예외를 발생시키기보다는 항상 오류를 처리하도록 노력하십시오(예: 0으로 나누기).

좋은 습관은 다음과 같습니다 예외를 번역하다.그냥 기록하지 마세요.예외가 발생한 구체적인 이유를 알고 싶다면 특정 예외를 발생시키세요.

public void connect() throws ConnectionException {
   try {
       File conf = new File("blabla");
       ...
   } catch (FileNotFoundException ex) {
       LOGGER.error("log message", ex);
       throw new ConnectionException("The configuration file was not found", ex);
   }
}

자체 예외를 사용하여 내장 예외를 래핑합니다.이렇게 하면 예외를 포착할 때 알려진 오류와 알 수 없는 오류를 구분할 수 있습니다.이는 예상 및 예상치 못한 실패에 반응하기 위해 예외를 던질 가능성이 있는 다른 메서드를 호출하는 메서드가 있는 경우 유용합니다.

표준 예외 처리 스타일을 조회하고 싶을 수도 있지만 제가 이해한 바는 다음과 같습니다.예외에 추가 세부 정보를 추가할 수 있는 수준이나 사용자에게 예외를 표시할 수준에서 예외를 처리합니다.

귀하의 예에서는 예외를 잡아서 기록하고 다시 던지는 것 외에는 아무것도 하지 않습니다.당신이 하고 있는 일이 로그를 기록하는 것뿐이라면 모든 메소드 내부 대신에 하나의 try/catch로 가장 높은 수준에서 그것을 잡아내는 것이 어떨까요?

예외를 다시 발생시키기 전에 유용한 정보를 예외에 추가하려는 경우에만 해당 계층에서 처리합니다. 일반적으로 누구에게도 거의 의미가 없는 낮은 수준 예외 텍스트 이상의 유용한 정보를 포함하는 새로운 예외로 예외를 래핑합니다. 아무런 맥락도 없이..

예외가 처리되는 곳에서는 사용할 수 없는 데이터를 기록해야 하는 경우가 있습니다.그런 경우에는 해당 정보를 얻기 위해 로그를 작성하는 것이 적절합니다.

예를 들어(Java 의사 코드):

public void methodWithDynamicallyGeneratedSQL() throws SQLException {
    String sql = ...; // Generate some SQL
    try {
        ... // Try running the query
    }
    catch (SQLException ex) {
        // Don't bother to log the stack trace, that will
        // be printed when the exception is handled for real
        logger.error(ex.toString()+"For SQL: '"+sql+"'");
        throw ex;  // Handle the exception long after the SQL is gone
    }
}

이는 이벤트 로그를 버퍼링하지만 예외 발생과 같은 트리거 이벤트가 없으면 기록하지 않는 소급 로깅(내 용어)과 유사합니다.

모든 예외를 기록해야 한다면 이는 환상적인 아이디어입니다.즉, 다른 이유 없이 모든 예외를 기록하는 것은 그리 좋은 생각이 아닙니다.

일반적으로 UI 또는 웹 서비스 코드인 가장 높은 수준에서 로그를 기록할 수 있습니다.여러 번 로깅하는 것은 일종의 낭비입니다.또한 로그를 보면 전체적인 내용을 알고 싶어집니다.

우리 애플리케이션 중 하나에서 모든 페이지는 BasePage 개체에서 파생되며 이 개체는 예외 처리 및 오류 로깅을 처리합니다.

그것이 유일한 일이라면 해당 클래스에서 try/catch를 제거하고 이를 처리하는 책임이 있는 클래스에 예외가 발생하도록 하는 것이 더 낫다고 생각합니다.이렇게 하면 예외당 하나의 로그만 얻을 수 있어 더 명확한 로그를 얻을 수 있고 스택 추적을 기록할 수도 있으므로 예외가 발생한 위치를 놓치지 않을 수 있습니다.

내 방법은 처리기에서만 예외를 기록하는 것입니다.말하자면 '진짜' 핸들러입니다.그렇지 않으면 로그를 읽기가 매우 어렵고 코드가 덜 구조화됩니다.

예외에 따라 다릅니다.이런 일이 실제로 발생하지 않는다면 반드시 기록할 것입니다.다른 방법으로는:이 예외가 예상된다면 애플리케이션 디자인에 대해 생각해 봐야 합니다.

어느 쪽이든:최소한 다시 던지거나 포착하거나 기록하려는 예외를 지정해야 합니다.

public foo(..)
{
   try
   {
     ...
   }
   catch (NullReferenceException ex) {
     DoSmth(e);
   }
   catch (ArgumentExcetion ex) {
     DoSmth(e);
   }
   catch (Exception ex) {
     DoSmth(e);
   }
}

계층 경계에 로그인하려고 합니다.예를 들어 비즈니스 계층을 n 계층 애플리케이션의 물리적으로 분리된 시스템에 배포할 수 있는 경우 이러한 방식으로 오류를 기록하고 발생시키는 것이 합리적입니다.

이런 방식으로 서버에 예외 로그가 생기고 무슨 일이 일어났는지 알아내기 위해 클라이언트 컴퓨터를 뒤질 필요가 없습니다.

저는 Remoting 또는 ASMX 웹 서비스를 사용하는 애플리케이션의 비즈니스 계층에서 이 패턴을 사용합니다.WCF를 사용하면 ChannelDispatcher(완전히 다른 주제)에 연결된 IErrorHandler를 사용하여 예외를 가로채서 기록할 수 있으므로 try/catch/throw 패턴이 필요하지 않습니다.

예외 처리 전략을 개발해야 합니다.나는 잡아서 다시 던지는 것을 권장하지 않습니다.불필요한 로그 항목 외에도 코드를 읽기가 더 어려워집니다.예외에 대해 생성자의 로그에 기록하는 것을 고려하십시오.이는 복구하려는 예외에 대한 try/catch를 예약합니다.코드를 읽기 쉽게 만듭니다.예기치 않거나 복구할 수 없는 예외를 처리하려면 프로그램의 가장 바깥쪽 계층 근처에서 try/catch를 사용하여 진단 정보를 기록해야 할 수 있습니다.

그런데 이것이 C++인 경우 catch 블록은 추가 문제의 잠재적 원인이 될 수 있는 예외 개체의 복사본을 생성합니다.예외 유형에 대한 참조를 잡아보세요.

  catch (const Exception& ex) { ... }

이것 Software Engineering Radio 팟캐스트는 오류 처리 모범 사례에 대한 매우 좋은 참고 자료입니다.실제로 2개의 강의가 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top