2016-11-29 1 views
3

우리는 다음과 같은 형태 저장소 코드를 가지고 :예외 로깅

public class PieRepository 
{ 

    public void AddCherryPie(string incredientA) 
    { 
     try{ 
      ... 
     } 
     catch(Exception ex){ 
      log("Error in AddCherryPie(" + incredientA + ")"); 
      throw new Exception("Error in AddCherryPie(" + incredientA + ")", ex); 
     } 
    } 

    public void AddApplePie(string incredientA, string incredientB) 
    { 
     try{ 
      ... 
     } 
     catch(Exception ex){ 
      log("Error in AddApplePie(" + incredientA + "," + incerdientB + ")"); 
      throw new Exception("Error in AddApplePie(" + incredientA + "," + incredientB ")", ex); 
     } 
    } 
} 

그래서 try -> catch -> log -> throw new이 저장소 방법과 프로젝트의 다른 중요한 방법의 대부분에 존재한다.

오늘 우리는 누군가가 이런 유형의 오류 처리를 제안한 적이 없으므로이 문제에 대해 논쟁을 벌였습니다. 그러나 주된 주장은 우리와 지원이 정확히 무슨 일이 일어 났는지를 알아야한다는 것과 다른 유형의 예외 처리가 필요 없다는 것입니다. 우리에게 정확히 이것을주지 마라. 누군가가 괜찮은지 말할 수 있겠는가?

편집 : 오류가 발생하면 원본 예외 메시지가 추가되었습니다.

+0

코드는 예외를 catch 한 다음 사용하지 않고 유용한 디버그 정보를 포함하지 않는 새로운 예외를 throw합니다. StackTrace 등이 없으면 정확히 무슨 일이 일어 났는지 알 수 없으므로 '우리는 정확히 무슨 일이 일어 났는지 알 필요가 있습니다.'라는 주장은 의미가 없습니다. 적어도 어딘가에 예외를 기록한 다음 유용한 메시지를 사용자에게 제시해야합니다. – Equalsk

+0

로그 측면에서 NLog 또는 다른 타사 솔루션을 사용할 수 있습니다 (NLog에 매우 만족합니다). – Tuco

답변

3

새 예외를 만들지 마십시오. 원래 예외를 던지거나 내부 예외로 적어도 포함하여 다시 게시하지 마십시오. 그렇지 않으면 stacktrace가 더 이상 체인이 올바르지 않습니다. throw new Exception에서 발생한 것입니다.

더 나은입니다

public class PieRepository 
{ 
    public void AddCherryPie(string incredientA) 
    { 
     try{ 
      ... 
     } 
     catch(Exception ex){ 
      log("Error in AddCherryPie(" + incredientA + ")"); 
      throw 
     } 
    } 

또는 개인적으로

public void AddApplePie(string incredientA, string incredientB) 
    { 
     try{ 
      ... 
     } 
     catch(Exception ex){ 
      log("Error in AddApplePie(" + incredientA + "," + incerdientB + ")"); 
      throw new Exception("Error in AddApplePie(" + incredientA + "," + incredientB ")", ex); // add original exception as inner exception! 
     } 
    } 
} 

, 나는 정말 그냥 throw 대신 throw new Exception("...", originalException)를 사용하는 것이 좋습니다. 항상 원래 예외를 버리면 나중에 흐름에서 수행 할 작업을 결정할 수 없습니다. 사용자에게 어떤 오류가 있습니까? 프로그래밍 오류보다 데이터베이스 오류 또는 유효성 검사 오류 (메시지 "데이터베이스를 사용할 수 없음"또는 "재료 A를 찾을 수 없음"과 같은)에 따라 조치가 다를 수 있습니다.

전체적인 방법이 유효합니다. 메소드의 인수와 오류 컨텍스트를 알기 때문에 조기에 로그하는 것이 좋습니다. 재실행하면 사용자에게 메시지를 표시하거나 예외의 유형에 따라 다른 조치를 취함으로써 UI의 오류를 다시 처리 할 수 ​​있습니다. 이 글을 읽을 오류 메시지에 대한 몇 가지 생각에 대한

: 당신이 정말로 모든 방법을 사용 Aspect 지향적 인 프로그래밍이 작업을 수행하려면 http://blog.ploeh.dk/2014/12/23/exception-messages-are-for-programmers/

이제 (AOP는 https://en.wikipedia.org/wiki/Aspect-oriented_programming 참조). 이런 종류의 기술로 예를 들어 속성을 사용하여 수행 할 수 있습니다. 예를 들어 PostSharp를 사용하십시오 : http://doc.postsharp.net/exception-handling. 로깅이 코드를 복잡하게하지 않아야합니다.

+0

원래 예외가 코드에 포함되어 있으며 의사 코드에 추가하는 것을 잊었습니다. 나는 단지'throw '를 사용했으나 인수는 예외가 충분히 친숙하지 않다는 것입니다. 내 생각에 – Silencer

+0

예외 메시지는 사용자에게 제공해서는 안되지만 예외 유형에 따라 달라야합니다. 오류에서 "Error in MethodXXX"라고 말하면 사용자가 취해야 할 조치는 무엇입니까? 방법에 대해 알지 못합니다. 상관하지 않습니다. 사용자는 그가 재 시도 할 수 있는지 여부 또는 오류의 부작용이 무엇인지 알고 싶어합니다. –

+0

나는'Exception' 클래스를 전혀 던지지 말 것을 강력히 권한다. 보다 구체적인 예외 유형을 사용해야합니다. 그렇지 않으면 예외를 처리하려는 특정 catch 절을 작성할 수 없습니다. 나는 Exception을 던지거나 만들지 않는 좋은 이유를 생각할 수 없다. – Kyle

0

몇 가지 방법으로이 문제를 해결할 수 있습니다. 다음,

public void AddApplePie(string incredientA, string incredientB) 
{ 
    try 
    { 
     ... 
    } 
    catch(Exception ex) 
    { 
     ex.Data["IncredientA"] = incredientA; 
     ex.Data.Add("IncredientB", incredientB); 
     throw; 
    } 
} 

또는 추가 정보가 포함 된 사용자 지정 예외를 만들 수있는 내부 예외로 원래 제외 하나를 던져 : 가장 간단한 예외 클래스의 데이터 속성을 사용하는 것입니다.

는 다음 사항을 고려, 당신에게 아이디어를 제공하려면 :

public void AddApplePie(string incredientA, string incredientB) 
{ 
    try 
    { 
     ... 
    } 
    catch(Exception ex) 
    { 
     throw new PieRepositoryException("Error adding apple pie.", ex, incredientA, incredientB); 
    } 
} 

귀하의 높은 수준의 코드는 다음 특정 예외를 잡으려고하거나 전략을 구현할 수, 캐치 :

public class PieRepositoryException : Exception 
{ 
    public PieRepositoryException(string message, Exception innerException, params string[] ingredients):base(message, innerException) 
    { 
     Ingredients = ingredients; 
    } 

    public property string[] Ingredients { get; private set; } 
} 

그런 다음이 작업을 수행 할 수 있습니다 일반 속성을 사용하고 모든 속성을 로그에 출력하거나 형식자를 사용하여 유형을 기반으로 로그에 출력 할 수 있습니다.

+0

리포지토리 매개 변수는 int에서 객체까지 모든 것이 될 수 있습니다.이 모든 것이 문자열로 표현 될 수 있으므로 실제로 큰 문제는 아니지만 문제의 주된 아이디어는'try -> catch -> log -> 모든 메소드에서 새로운'을 throw합니다. – Silencer

1

모든 메서드에서 똑같은 동작을 사용하는 것처럼 보였으므로 aspect 지향 프로그래밍 프레임 워크를 사용하는 것이 좋습니다.

그런 식으로 사용자 지정 예외 처리 논리가 포함 된 애스펙트 (특성)를 정의 할 수 있으며 모든 메서드에서 동일한 상용구 코드가 사용되지 않도록 할 수 있습니다.

당신은 측면을 사용하는 경우 귀하의 클래스는 다음과 같습니다

public class PieRepository 
{ 
    [LogExceptions] 
    public void AddCherryPie(string incredientA) 
    { 
     ... 
    } 
} 

그리고 당신의 측면은 다음과 같을 수 있습니다 :

public class LogExceptionsAttribute : OnExceptionAspect 
{ 
    public override void OnException(MethodExecutionArgs args) 
    { 
     // Create a log message, you can access the method info and parameters 
    } 
} 

당신은 측면을 사용하도록 방법을 속성 경우 측면이 될 것입니다 메서드가 실행될 때마다 호출되므로 컴파일 타임 직조를 지원하는 프레임 워크를 사용해야합니다 (런타임 위빙과는 달리 응용 프로그램의 성능에 큰 영향을줍니다).

자세한 예제는 http://doc.postsharp.net/exception-handling을 참조하십시오.

+0

고마워, 이건 대단한 대답인데, Peter Bons가 첫번째였다. 나쁘다. 나는 대답으로 둘 다 표시 할 수 없다. ( – Silencer