다중 계층 구조 : 오류 로그 처리를 어디에서 구현해야합니까?


17

현재 멀티 레이어 아키텍처로 큰 하위 시스템을 리팩토링하고 있으며 효과적인 오류 로깅 처리 전략을 설계하는 데 어려움을 겪고 있습니다.

내 아키텍처가 다음 3 가지 레이어로 구성되어 있다고 가정 해 보겠습니다.

  • 공용 인터페이스 (IE MVC 컨트롤러)
  • 도메인 레이어
  • 데이터 액세스 계층

혼란의 근원은 오류 로깅 처리를 구현 해야하는 곳입니다.

  1. 가장 쉬운 해결책은 최상위 수준에서 로깅을 구현하는 것입니다 (즉, 공용 인터페이스 \ MVC 컨트롤러). 그러나 이것은 다른 계층을 통해 예외를 버블 링 한 다음 로깅하는 것을 의미하기 때문에 잘못 느낍니다. 소스에서 예외를 기록하는 대신.

  2. 정보가 가장 많기 때문에 소스에서 예외를 기록하는 것이 가장 좋습니다. 이것에 대한 내 문제는 모든 예외를 포착하지 않고 소스에서 모든 예외를 포착 할 수 없다는 것입니다. 도메인 / 공용 인터페이스 계층에서는 아래 계층에서 이미 포착, 기록 및 다시 throw 된 예외를 포착하게됩니다. .

  3. 또 다른 가능한 전략은 # 1과 # 2의 혼합입니다. 이를 통해 레이어에서 특정 예외를 포착하고 (즉 SqlExceptions, 데이터 액세스 계층에서 캐치, 로깅 및 다시 던지기 ) 가장 많이 포착되지 않은 예외를 최상위 레벨에 기록합니다. 그러나 이미 처리 된 오류와 그렇지 않은 오류를 구별 할 수 없기 때문에 최상위 수준에서 모든 예외를 포착하고 다시 기록해야합니다.

이제 이것은 대부분의 소프트웨어 응용 프로그램에서 문제가되므로이 문제에 대한 표준 솔루션이 있어야 소스에서 예외가 발생하고 한 번 기록됩니다. 그러나 나는 이것을 직접하는 방법을 볼 수 없습니다.

이 질문의 제목은 ' 멀티 티어 응용 프로그램에서 예외 로깅 '과 매우 유사 하지만 해당 게시물의 답변에 세부 정보가 부족하고 내 질문에 대답하기에 충분하지 않습니다.


1
때때로 사용하는 한 가지 방법은 내 자신의 Exception (또는 RuntimeException) 서브 클래스를 작성하여 원래 예외를 중첩 된 예외로 포함시키는 것입니다. 물론 그것은 상위 수준에서 예외를 캡처 할 때 예외 유형을 확인해야 함을 의미합니다 (내 예외는 다시 발생하고 다른 예외는 기록되어 새 예외의 인스턴스에 포함됩니다). 그러나 나는 오랫동안 솔로로 일해 왔으므로 "공식적인"조언을 줄 수 없습니다.
SJuan76

4
The easiest solution would be to implement the logging at the top level- 이 작업을 수행. 소스에서 예외를 기록하는 것은 좋은 생각이 아니며 내가 겪은 모든 응용 프로그램은 디버깅 할 PITA였습니다. 예외를 처리하는 것은 호출자의 책임입니다.
Justin

특정 구현 기술 / 언어를 염두에두고있는 것 같습니다. 그렇지 않으면 "기록 된 예외와 그렇지 않은 예외를 구별 할 수 없습니다"라는 문장을 이해하기 어렵습니다. 더 많은 맥락을 줄 수 있습니까?
Vroomfondel

@Vroomfondel-당신이 맞아요. C #을 사용하고 있으며 각 레이어에 코드를 줄 바꿈하면 각 레이어 try{ ... } catch(Exception ex) { Log(ex); }에 동일한 예외가 기록됩니다. (또한 코드 기반의 모든 계층에서 모든 예외를 잡는 것은 나쁜 습관처럼 보입니다.)
KidCode

답변:


18

당신의 질문에 :

가장 쉬운 해결책은 최상위 수준에서 로깅을 구현하는 것입니다.

예외 버블을 최상위 수준으로 올리는 것은 절대적으로 정확하고 그럴듯한 방법입니다. 상위 계층 방법 중 어느 것도 실패 후 일부 프로세스를 계속하려고 시도하지 않으며 일반적으로 성공하지 못합니다. 또한 잘 갖추어 진 예외에는 로깅에 필요한 모든 정보가 포함되어 있습니다. 예외에 대해 아무 것도하지 않으면 코드를 깨끗하게 유지하고 실패 대신 기본 작업에 집중할 수 있습니다.

정보가 가장 많기 때문에 소스에서 예외를 기록하는 것이 가장 좋습니다.

반은 맞습니다. 네, 가장 유용한 정보가 있습니다. 그러나 즉시 기록하는 대신이 모든 것을 예외 객체 (아직없는 경우)에 넣는 것이 좋습니다. 낮은 수준으로 로그인 한 경우에도 발신자에게 작업을 완료하지 않았다고 알리기 위해 예외를 포기해야합니다. 이것은 같은 이벤트의 여러 로그로 끝납니다.

예외

내 주요 지침은 최상위 수준에서만 예외를 포착하고 기록하는 것입니다. 그리고 아래의 모든 계층은 필요한 모든 실패 정보가 최상위 수준으로 전송되도록해야합니다. Java와 같은 단일 프로세스 응용 프로그램 내에서 이것은 대부분 최상위 외부에서 시도 / 캐치 또는 로깅을 시도하지 않음을 의미합니다.

때로는 예외가 발생했을 때 실행 된 SQL 문 및 매개 변수와 같이 원래 예외에서 사용할 수없는 일부 컨텍스트 정보가 예외 로그에 포함되기를 원할 수도 있습니다. 그런 다음 원래 예외를 포착하고 원래 예외와 컨텍스트를 포함하여 새 예외를 다시 던질 수 있습니다.

물론 실제 생활은 때때로 다음을 방해합니다.

  • Java에서는 때로는 고정 된 메소드 서명을 준수하기 위해 예외를 잡아서 다른 예외 유형으로 랩핑해야합니다. 그러나 예외를 다시 발생시키는 경우, 다시 발생하는 예외에 나중에 로깅에 필요한 모든 정보가 포함되어 있는지 확인하십시오.

  • 프로세스 간 경계를 넘어가는 경우 종종 스택 추적을 포함하여 전체 예외 개체를 기술적으로 전송할 수 없습니다. 물론 연결이 끊어 질 수도 있습니다. 따라서 서비스가 예외를 기록한 다음 가능한 한 많은 장애 정보를 라인 전체에서 클라이언트로 전송하기 위해 최선을 다해야 할 시점이 있습니다. 서비스는 실패 응답을 받거나 연결이 끊어진 경우 시간 초과가 발생하여 클라이언트가 실패 알림을 받도록해야합니다. 이로 인해 일반적으로 서비스 내부 (자세한 내용은 한 번)와 클라이언트 최상위 레벨에서 한 번 같은 로그가 두 번 기록되지 않습니다.

벌채 반출

예외 로깅뿐만 아니라 일반적인 로깅에 대한 문장을 추가하고 있습니다.

예외적 인 상황 외에도 응용 프로그램의 중요한 활동이 로그에 기록되기를 원합니다. 따라서 로깅 프레임 워크를 사용하십시오.

로그 레벨에주의하십시오 (디버그 정보 및 심각한 오류가 다르게 표시되지 않은 로그를 읽는 것은 고통 스럽습니다!). 일반적인 로그 수준은 다음과 같습니다.

  • 오류 : 일부 기능을 복구 할 수 없습니다. 그렇다고 반드시 전체 프로그램이 중단 된 것은 아니지만 일부 작업을 완료 할 수 없습니다. 일반적으로 실패를 설명하는 예외 개체가 있습니다.
  • 경고 : 이상한 일이 발생했지만 어떤 작업도 실패하지 않았습니다 (이상한 구성 감지, 일시적인 연결 고장으로 인해 재시도 등)
  • 정보 : 로컬 시스템 관리자에게 중요한 프로그램 작업을 전달하려고합니다 (구성 및 소프트웨어 버전으로 서비스 시작, 데이터 파일을 데이터베이스로 가져 오기, 사용자가 시스템에 로그인하면 아이디어를 얻습니다 ...).
  • 디버그 : 개발자가 어떤 문제를 디버깅 할 때보고 싶어하는 것 (그러나이 버그 나 특정 버그의 경우 실제로 필요한 것을 미리 알 수는 없습니다. 예견 할 수 있으면 버그를 수정하게됩니다. ). 항상 유용한 한 가지는 외부 인터페이스에 활동을 기록하는 것입니다.

프로덕션에서는 로그 레벨을 INFO로 설정하십시오. 결과는 시스템 관리자에게 유용하므로 진행 상황을 알 수 있습니다. 로그 및 경고의 절반에있는 모든 오류에 대해 지원 또는 버그 수정을 요청하십시오.

실제 디버깅 세션 중에 만 DEBUG 레벨을 사용하십시오.

로그 항목을 적절한 범주 (예 : 항목을 생성하는 코드의 정규화 된 클래스 이름)로 그룹화하면 프로그램의 특정 부분에 대한 디버그 로그를 켤 수 있습니다.


자세한 답변을 주셔서 감사합니다. 로깅 부분도 정말 감사합니다.
KidCode 2009 년

-1

나는 downvotes를 위해 자신을 보강하고 있지만, 사지로 나가서 이것에 동의 할 수 있는지 확실하지 않다고 말합니다.

버블 링 예외는 다시 로깅하는 횟수가 훨씬 적으므로 별다른 이점이없는 추가 노력입니다. 소스 (예, 가장 쉬운 것)에서 예외를 포착하고 기록한 다음 예외를 다시 발생시키지 말고 "오류"를 호출자에게보고하십시오. "-1", null, 빈 문자열, 열거 형 등 무엇이든. 호출자는 호출이 실패했다는 사실 만 알면됩니다. 그리고 그것들은 당신의 통나무에있을 것입니다. 드문 경우이지만 발신자에게 세부 정보가 필요하면 계속해서 거품을냅니다. 그러나 자동 생각하지 않는 기본값은 아닙니다.


3
반환 값으로 오류를보고 할 때 발생하는 문제는 다음과 같습니다. 1. 호출자가 실패를 처리하는 경우 특수 값을 확인해야합니다. 그러나 잠깐만, null아니면 빈 문자열입니까? -1 또는 음수입니까? 2. 발신자가 신경 쓰지 않으면 (즉, 확인하지 않으면) 원래 원인과 관련이없는 후속 오류 (예 : a)가 발생합니다 NullPointerException. 또는 더 나쁜 것은 : 잘못된 값으로 계산이 계속됩니다. 3. 호출자가 신경을 쓰지만 프로그래머가이 방법이 실패했다고 생각하지 않으면 컴파일러는이를 상기시키지 않습니다. 예외는 이러한 문제가 없으므로 잡거나 다시 던질 수 있습니다.
siegi

1
죄송합니다. C 언어가 시작된 1970 년대에 당신이 묘사 한 접근법 (예외 반환 값으로 예외를 대체)은 최첨단 기술이며 현대 언어에는 예외가있는 많은 이유가 있습니다. 예외를 올바르게 사용하면 강력한 코드를 훨씬 쉽게 작성할 수 있습니다. 그리고 당신의 "버블 링 예외 [...]는 추가 노력 [...]"은 명백한 잘못입니다 : 예외에 대해서는 아무 것도하지 않고, 스스로 스스로 거품을 일으킬 것입니다.
Ralf Kleberhoff
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.