로깅 코드를 비즈니스 로직 외부에서 완전히 유지할 수 있습니까?


12

AOP의 도움으로 비즈니스 로직에서 로깅 코드를 제거 할 수 있습니다. 그러나 나는 간단한 것들 (즉, 로깅 방법 입력 / 종료 및 매개 변수 값)을 기록하는 데만 사용할 수 있다고 생각합니다.

그러나 비즈니스 로직에 무언가를 기록해야하는 경우 어떻게해야합니까? 예 :

public void SomeDomainMethod(string id)
{
   //Get user by Id
   User user = Users.Get(id);
   if (user == null)
   {
      Log.Warn("user is not existed");        //<----------------- Log A
      throw new InvalidOperationException("user is not existed");
   }

   //Step 1 
   while(true)
   {
       //do something
   }
   Log.Info("Step 1 is completed");            //<----------------- Log B

   //Step 2
   while(true)
   {
       //do something
   }
   Log.Info("Step 2 is completed");            //<----------------- Log C

}

위의 샘플 방법은 명확하지 않을 수 있습니다. 여기서 보여 드리고자하는 방법은 도메인 관점에서 가장 작은 단위로 처리해야한다는 것입니다. 더 작은 조각으로 나눠서는 안됩니다.

메소드에서 3 가지 로깅 코드 이상으로 이동할 수 있습니까? 그러한 상황에 대한 모범 사례는 무엇입니까?


귀하의 예제 "Step1"및 "Step2"로그는 비즈니스 로직 감사 추적의 일부이고 첫 번째는 기술 로깅이어야합니다. 내가 먼저 이것을 정렬합니다 ...
tofro

답변:


1

확실한!

그러나 내 경험상 유용한 로깅 에는 두 가지 일반적인 유형이 있습니다.

모든 로그 : 프로파일 링 API를 통해 작성된 로그. 성능 문제를 식별하고 예외를보고하는 데 좋습니다. 시끄러운.

비즈니스 이벤트 로그 : 비즈니스 로직에서 호출 된 로그. 비즈니스가 관심을 가질만한 모든 것. 최소 소음. 주목할만한 논리적 인 "비즈니스"이벤트. 감사 및 KPI에 적합

그래서 저는 두 가지를 강력히 제안합니다. 먼저 New Relic과 같은 다른 모니터링 도구의 기능을 수행 하고 .NET 프로파일 링 API 1을 사용하십시오 . 둘째, 비즈니스 로직에 논리적 비즈니스 이벤트 를 기록하십시오 . 특정 이벤트의 기록을 유지하는 것은 비즈니스 논리입니다.

그리고 일반적으로 로깅 2에 대해 AOP를 제안하지는 않습니다 . 내 경험상 모든 것을 원합니다. 즉 프로파일 러를 사용하거나 논리 / 비즈니스 이벤트를 원합니다. 후자의 경우 비즈니스 로직에서 로거 호출하는 것이 더 간단하다고 생각합니다 .


1. 그러나 진지하게, 수천 시간을 절약하고 기존 프로파일 러 도구를 사용하십시오 ...

2. 물론 이것은 당신이 한 측면 이 비즈니스 규칙을 숨길 수있는 좋은 장소가 아니라는 나의 의견을 공유한다고 가정합니다 !


나는 "비즈니스 이벤트 로그"에 동의하고 다른 사람들의 대답과 마찬가지로 로그 코드를 비즈니스 논리에 유지합니다. "모든 로그"부분에서는 SRP를 따르고 비즈니스 로직을 오염시키지 않기 때문에 AOP 솔루션을 사용하는 것을 선호합니다. 어쨌든 먼저 프로파일 링 API를 살펴 보겠습니다.
Charlie

10

물론 AOP를 쉽게 사용할 수 있습니다. 단순히 부품을 리팩터링

  • ID로 사용자 확보
  • 1 단계
  • 2 단계

별도의 방법 (당신은 당신의 코드 청소기를 만들기 위해 중 하나를 했어야으로). 이제 선택한 메소드 호출을 기록하도록 AOP 프레임 워크를 쉽게 구성 할 수 있습니다 ( 여기 참조 ). 예외는 호출자가 직접 기록 할 수 있으므로이를 비즈니스 로직에서 가져 오기 위해 AOP를 사용할 필요가 없습니다.

편집하려면 :

여기서 보여주고 싶은 것은이 방법이 도메인 관점에서 가장 작은 단위로 취급되어야한다는 것입니다. 더 작은 조각으로 나눌 수 없습니다

왜 안됩니까? "비즈니스 로직 컨텍스트"에서 로깅 할 가치가있는 "무언가"를 기록하려는 경우이 "무언가"에 적절한 이름을 부여 할 수있는 경우 대부분의 경우 코드를 메소드로 리팩토링하는 것이 좋습니다. 자체. AOP를 사용하려면 로깅 요구 사항에 관계없이 코드를 구조화 한 방식으로 코드를 구조화해야합니다. 이를 AOP의 단점으로 해석하거나 코드 구조를 개선 할 수있는 피드백을 제공하므로 이점으로 해석 할 수 있습니다.


내 예가 충분히 명확하지 않은 것은 나쁘다. 이 예제에서 실제로 보여주고 싶은 것은 방법이 도메인 관점에서 가장 작은 단위이며 더 작은 조각으로 나눌 수 없다는 것입니다.
Charlie

@Charlie : 예제는 완벽합니다. 여기서 오해는 아마도 단계보다 더 큰 방법을 사용하는 것이 좋습니다. 그리고 그것은 IMHO 잘못입니다, 그것은 좋은 생각이 아닙니다. 로깅 할 가치가있는 다른 단계가 있다는 것은 명백한 신호입니다.이 단계에는 추상화, 자체 이름, 따라서 자체 메소드가 있어야합니다.
Doc Brown

@Charlie는 당신의 유닛이나 작업에 의해 호출되는 3 개의 개인 메소드를 막을 수있는 것이 없습니다. 외부 에서이 방법은 동일하게 유지되었지만 이제 로깅에 필요한 추상화가 있습니다.
Rémi

우려 사항을 기록하여 코드 구조를 구동하려는 경우이 방법이 좋습니다. 때로는 다른 무언가로 운전하고 싶을 수도 있습니다.
John Wu

@ JohnWu : 코드 구조는 로깅 요구 사항에 관계없이 다른 우려 / 단계를 반영해야합니다. 이것이 코드 구조를 이끄는 것입니다. 이 문제가 해결되면 AOP를 통해 로깅을 수행 할 수 있습니다. 이는 코드에 더 나은 구조를 제공하는 "부수 효과"입니다. 따라서 코드 구조를 구동하는 것은 로깅 문제가 아니라고 생각합니다. 로깅에 AOP를 사용해야하는 요구 사항이 있으면 코드에 필요한 구조가 누락 된 것보다 더 투명 해집니다.
Doc Brown

3

로깅은 비즈니스 요구 사항의 일부가 아니라면 코드에서 완전히 벗어나는 것이 가장 좋습니다.

즉, "1 단계 완료"와 같은 항목을 기록하지 않으려는 것입니다. 처음에는 디버깅에 유용 할 수 있지만 프로덕션 환경에서는 절대로 볼 수없는 기가 바이트의 쓰레기가 생성됩니다.

Step1Complete가 추가 조치가 필요한 일종의 비즈니스 이벤트 인 경우 클래스에 ILogger 또는 이와 유사한 것을 주입하지 않고도 구식 이벤트를 통해 노출 될 수 있습니다


그것이 내가 생각한 것입니다. 도메인 / 비즈니스 모델 POCO 내에서 로깅에 대한 합리적인 사례를 제시 할 수 없습니다. 로깅은 핵심 비즈니스 모델 인 IMO 외부에 자연스럽게 들어가는 경향이 있습니다.
jleach

2

몇 가지 일반적인 패턴을 사용하여 비즈니스 로직에서 로깅 코드를 가져올 수 있습니다. 그러나 그렇게 할 가치가 없을 수도 있습니다

예를 들어 리스너 (수공예 하나 또는 이벤트 버스 등)를 사용하면 코드가 다음과 같이 표시됩니다.

public void SomeDomainMethod(string id)
{
   //Get user by Id
   User user = Users.Get(id);
   if (user == null)
   {
      listener.OnUserNotFound(userId);
      throw new InvalidOperationException("user is not existed");
   }

   //Step 1 
   while(true)
   {
       //do something
   }
   listener.OnStep1Finished(......);

   ...

}

리스너에서 로깅을 구현함으로써 비즈니스 로직에는 더 이상 로깅 로직이 없습니다.

그러나 논리의 의미있는 이벤트를 항상 정의 할 수있는 것은 아니기 때문에 이것이 항상 현실적이지는 않을 수 있습니다.

또 다른 접근 방식은 실행중인 프로세스에 주입 할 수있는 Solaris의 Dtrace와 같은 메커니즘을 사용하는 것입니다 (C #에서 비슷한 일을 할 수 있다고 생각합니까?) 로깅 및 통계 수집을 런타임에 정의 할 수 있습니다. 여전히 다른 결점이 있습니다.


AOP가 해결하려고하는 한 가지 문제는 "비즈니스 코드"와 섞여있는 비 업무용 코드 (예 : 로깅 호출)를 읽을 수 없게되는 문제입니다. "청취자"로 "로거"를 교체해도 문제가 해결되지 않습니다. 코드의 가독성이 변경되지 않았습니다.
Doc Brown

2

또 다른 방법은 비즈니스 로깅과 기술 로깅을 분리하는 것입니다. 그런 다음 비즈니스 로깅을 "감사"라고하고 스토리지 기간과 같은 특정 비즈니스 규칙 세트와 비즈니스 활동 모니터링과 같은 처리 규칙을 적용 할 수 있습니다.

반면에, 기술 로깅 또는 간단히 "로깅"은 기술적 문제의 흔적을 남기는 최후의 수단입니다. 로그 메시지를 유지하지 못하면 비동기적이고 빠르며 견딜 수 있어야합니다. 또한 로그 메시지는 문제의 원인에 근접 할 수있는 가장 적은 수의 프록시를 통과해야합니다.

로깅의 논리는 매우 가변적이며 구현과 밀접하게 연결되어 있으므로 실제로 코드와 분리해야합니까?

감사의 논리는 도메인 논리로 간주되고 그에 따라 처리되어야합니다.

예를 들어, 6 각형 아키텍처에는 클라이언트, 스토리지 및 MQ (및 가능하면 메트릭 및 제어) 포트와 함께 감사 포트가있을 수 있습니다. 이 포트는 2 차 포트입니다. 즉,이 포트의 활동은 외부 시스템이 아닌 비즈니스 코어에 의해 트리거됩니다.


나는 두 종류의 벌목이 있다는 것에 매우 동의했다. 그러나 나는 로깅의 논리가 상당히 변하지 않으며 구현과 밀접하게 결합되어 있습니다. 기술 로깅을 의미합니까? 기술 로깅의 경우 메소드 입력 / 종료 및 메소드 외부에 더 나은 매개 변수 값을 기록하는 데 사용됩니다.
Charlie

@Charlie 예, "로깅"이란 기술 로깅을 의미합니다. 순수한 기능의 경우 시작 / 종료 / 매개 변수 값 로깅으로 충분합니다. 그런 다음 코스 또는 측면을 사용하거나 Logger 모나드를 사용할 수 있습니다. 그러나 순수한 기능은 테스트 가능하다는 점에서 뛰어납니다. 따라서 로거가 추적 해야하는 문제는 dev / debug 중에 해결 될 것입니다. 기술 로깅이 가장 많이 사용되는 불순한 기능을 사용하면 모든 부수적 인 호출 매개 변수 / 결과, 모든 예외를 기록하려고합니다.
iTollu

1

클래스 나 메소드에 직접 로깅을 피하는 방법 :

  1. 예외를 던지고 콜 트리에서 멀어지면 catch 블록에 로깅하십시오. 로그 수준을 캡처해야하는 경우 사용자 지정 예외를 throw 할 수 있습니다.

  2. 로깅을 위해 이미 계측 된 메소드를 호출하십시오.


1
로깅이 문제가있는 위치에 있고 "고정"가치가있는 것입니까?
whatsisname

1

로깅과 비즈니스 로직을 분리해야합니까? 수행되는 로깅은 작성된 비즈니스 로직과 일치하므로 동일한 클래스 / 기능에있는 것이 좋습니다. 더 중요한 것은 코드의 가독성을 향상시키는 데 도움이됩니다.

그러나 비즈니스 로직에서 로깅을 분리하려는 경우 사용자 정의 예외를 발생시키고 해당 예외를 로깅에 처리해야합니다.


0

아니요, C #에는 없습니다.

OP, 특정 질문에 대한 답변은 아니오, C #이 아닙니다. 다른 더 원시적 인 AOP 언어가있을 수 있지만, 내가 본 C #의 AOP에 대한 모든 접근 방식은 결합 지점 의 컨텍스트에서만 종횡비 동작을 적용 할 수 있습니다 . 즉, 하나의 코드 블록과 다른. 다른 동작을 호출하는 것 외에는, 특정 동작이 메소드 중간에 실행되지 않습니다.

특정 로깅 비트를 "Apsect-ize"할 수 있습니다

즉, 로그 쓰기가 아니라 로깅과 관련된 특정 문제를 추출 할 수 있습니다. 예를 들어, 메소드 시작시 실행 된 컷 포인트는 로깅 컨텍스트를 설정하고 모든 입력 매개 변수를 출력 할 수 있으며 종료시 예외를 포착하거나 로그를 영구 스토리지에 커밋 할 수 있습니다.

어쨌든 로그 작성 은 측면이 아닙니다.

어쨌든 로그 작성은 실제로 교차 문제가 아니라고 덧붙입니다. 최소한 디버그 로깅은 아닙니다. 이것에 대한 나의 증거는 당신이이 측면이 무엇을하는지 완전히 설명하는 교차 절단 요구 사항을 작성할 수 없다는 것입니다. 로그를 작성하는 목적은 논리와 각 메소드의 논리는 합리적으로 고유해야합니다 ( DRY 참조 ).

다시 말해서, 로그 기록과 기록되는 내용 사이에는 불가분의 논리적 의존성이 있습니다. 일반화 할 수 없습니다.

그러나 감사는

일종의 기능적 로깅 요구 사항 (예 : 부인 방지 요구 사항 을 지원하는 감사 로깅 )이있는 경우 일부는 메소드 중간에 이러한 로그 쓰기를 실행 해야하는 경우 측면 지향적 사고와 일치하는 방식으로 코드를 구성하지 않았습니다. 이 경우 필요한 세부 수준을 얻을 때까지 코드를 별도의 메서드로 추출해야합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.