로거는 비공개 정적이어야하는지 여부


103

로거를 정적으로 선언해야합니까? 일반적으로 로거에 대한 두 가지 유형의 선언을 보았습니다.

    보호 된 로그 로그 = new Log4JLogger (aClass.class);

또는

    개인 정적 로그 로그 = new Log4JLogger (aClass.class);

어느 것을 사용해야합니까? 둘 다의 장단점은 무엇입니까?


1
로깅은 교차 절단 문제입니다. Aspects를 사용하면 문제가 있습니다.
Dave Jarvis

4
static클래스 당 하나의 참조입니다. 비정 적은 인스턴스 당 하나의 참조입니다 (+ 초기화). 따라서 경우에 따라 수많은 인스턴스가있는 경우 후자는 메모리에 상당한 영향을 미칩니다. 빈번한 물체 에서 정전기 방지를 사용하지 마십시오 . 나는 항상 정적 버전을 사용합니다. (해야하는 대문자 LOG )
Anony - 무스 - 종료 될

2
이미 제안한대로 AOP 및 주석을 사용하십시오. 예 : jcabi.com/jcabi-aspects/annotation-loggable.html
yegor256

1
RobertHume 정적 버전 상수를 사용하고 있습니다. 그것이 바로 대문자 여야하는 이유입니다.
Has QUIT--Anony-Mousse

2
아니요, private static final Log log소문자 여야합니다. 로거는 상수가 아니며 로거는 정적 최종 객체 (변경 될 수 있음)입니다. 개인적으로 저는 항상 logger.
osundblad

답변:


99

비 정적 형식의 장점은 올바른 클래스 이름이 사용된다는 걱정없이 다음과 같이 (추상) 기본 클래스에서 선언 할 수 있다는 것입니다.

protected Log log = new Log4JLogger(getClass());

그러나 단점은 클래스의 모든 인스턴스에 대해 완전히 새로운 로거 인스턴스가 생성된다는 것입니다. 이것은 그 자체로 비싸지는 않지만 상당한 오버 헤드를 추가합니다. 이것을 피하려면 static대신 양식 을 사용하는 것이 좋습니다. 그러나 단점은 차례로 모든 개별 클래스에서 선언해야하고 로거 생성 중에 올바른 클래스 이름이 사용 된 모든 클래스에서주의를 기울여야한다는 것입니다.getClass() 하고 정적 컨텍스트에서 사용할 수 입니다. 그러나 평균 IDE에서는 이에 대한 자동 완성 템플릿을 만들 수 있습니다. 예 : logger+ ctrl+space.

반면에 이미 인스턴스화 된 로거를 캐시 할 수있는 공장에서 로거를 얻는 경우, 비 정적 형식을 사용하면 그다지 많은 오버 헤드가 추가되지 않습니다. 예를 들어 Log4j는 LogManager이러한 목적을 위해 있습니다.

protected Log log = LogManager.getLogger(getClass());

6
abstract Log getLogger();추상 클래스에서 선언 하십시오. 이 메서드를 구현하여 특정 인스턴스에 대한 정적 로거를 반환합니다. private final static Log LOG = LogManager.getLogger(Clazz.class);IDE 클래스 템플릿에 추가 합니다.
Anony - 무스 - 종료 될

2
slf4j :protected Logger log = LoggerFactory.getLogger(getClass());
Markus Pscheidt 2014

3
@BalusC getClass ()를 getLogger 메서드에 전달하는 문제는 현재 인스턴스의 클래스를 반환한다는 것입니다. 일반적으로 코드가있는 클래스와 관련된 로깅이 더 바람직합니다. 예를 들어 로깅 코드가 Parent 클래스에 있으면 실행중인 인스턴스가 Parent의 하위 클래스 인 Child 클래스의 인스턴스 인 경우에도 로깅이 Parent와 연결되기를 원합니다. getClass ()를 사용하면 Child와 잘못 연결됩니다
inor

@inor : "잘못됨"? 클래스를 추상화하지 않으려면 먼저 상속 된 getClass ()를 사용하지 않아야합니다. 로직이 정확히 수행 된 서브 클래스의 정보를 드러내므로 정확하고 유용하다고 생각하는 개발자가 있습니다.
BalusC

2
@ BalusC getLogger (getClass ())는 항상 하위 클래스의 이름을 잘못 로깅합니다. 로깅 클래스는 항상 getLogger (Clazz.class)를 수행하여 클래스 Clazz의 코드에 의해 작성된 로깅을 연관시켜야합니다. 실행중인 하위 클래스 (예 : SubClazz가 Clazz를 확장 함)를 알고 싶은 개발자는 SubClazz에서 수행해야합니다. getLogger (SubClazz.class) 및 다음과 같은 작업을 수행합니다. log.info ( "calling <something in my base class>");
inor

44

나는 모든 로거가 정적이어야한다고 생각했습니다. 그러나 wiki.apache.org의이 기사 클래스 로더 누출과 관련하여 몇 가지 중요한 메모리 문제를 제기합니다. 로거를 정적으로 선언하면 선언 클래스 (및 관련 클래스 로더)가 공유 클래스 로더를 사용하는 J2EE 컨테이너에서 가비지 수집되는 것을 방지합니다. 애플리케이션을 충분히 재배포하면 PermGen 오류가 발생합니다.

로거를 비 정적으로 선언하는 것 외에는이 클래스 로더 누수 문제를 해결할 수있는 방법이 없습니다.


4
정적 필드에도 메모리 누수 문제가 있다고 생각했습니다. 비정 적은 다른 사람들이 말했듯이 성능 문제가있을 수 있습니다. 그렇다면 이상적인 방법은 무엇입니까?
리앙

@piepera 당신이 언급 한 기사에서 설명한 주요 문제는 ""private static Log log = "를 사용하는 클래스가 아마도 다중의 조상에있는 ClassLoader를 통해 배포되는 경우를 고려할 때 각 응용 프로그램에서 로깅 수준을 제어하는 ​​기능입니다. 독립적 인 "응용 프로그램" ". 이 특정 상황에서 응용 프로그램이 "공통 접지"를 갖고 있고 "공통 접지"에서 클래스에 대한 로깅 수준이 결정되고 예, 모든 응용 프로그램에 대해 유지되기 때문에 문제가되지 않습니다. 마음이 클래스는 [로드] 이러한 응용 프로그램 이외의 것을
inor은

17

가장 중요한 차이점은 로그 파일에 미치는 영향입니다. 로그는 어떤 범주로 이동합니까?

  • 첫 번째 선택에서 하위 클래스의 로그는 수퍼 클래스의 범주에 속합니다. 그것은 나에게 매우 반 직관적 인 것 같습니다.
  • 첫 번째 경우의 변형이 있습니다.

    보호 된 로그 로그 = new Log4JLogger (getClass ());

    이 경우 로그 카테고리는 로그 된 코드가 어떤 개체에서 작동하고 있는지 알려줍니다.

  • 두 번째 선택 (개인용 정적)에서 로그 범주는 로깅 코드를 포함하는 클래스입니다. 따라서 일반적으로 기록되는 작업을 수행하는 클래스입니다.

마지막 옵션을 강력히 권장합니다. 다른 솔루션에 비해 다음과 같은 장점이 있습니다.

  • 로그와 코드 사이에는 직접적인 관계가 있습니다. 로그 메시지의 출처를 쉽게 찾을 수 있습니다.
  • 누군가가 로깅 수준 (범주별로 수행됨)을 조정해야하는 경우 일반적으로 특정 클래스에서 작성한 특정 메시지에 관심이 있거나 그렇지 않기 때문입니다. 카테고리가 메시지를 작성하는 클래스가 아닌 경우 레벨을 조정하기가 더 어렵습니다.
  • 정적 메소드에 로그인 할 수 있습니다.
  • 로거는 생성 된 모든 인스턴스가 아닌 시작시 클래스 당 한 번만 초기화 (또는 조회)하면됩니다.

또한 단점이 있습니다.

  • 메시지를 기록하는 모든 클래스에서 선언해야합니다 (슈퍼 클래스 로거 재사용 없음).
  • 로거를 초기화 할 때 올바른 클래스 이름을 입력하도록주의해야합니다. (하지만 좋은 IDE가 알아서 처리합니다).

4

제어 반전을 사용하고 로거를 생성자에 전달하십시오. 클래스 내부에 로거를 만들면 단위 테스트로 시간을 낭비하게 될 것입니다. 당신은 단위 테스트를 작성하고 있습니까?


5
쓸모없고 믿을 수 없을 정도로 부서지기 쉬운 소리를 생성하는 로깅을 검사하는 단위 테스트.
Michael

1
테스트중인 시스템에 따라 유용합니다. 때로는 로깅 만 액세스 할 수 있습니다.
Wayne Allen

@Wayne Allen은 단위 테스트를 할 때 정의에 따라 테스트 결과도 있습니다. 단위 테스트는하지만 테스트 결과가없는 상황을 제안하고 있습니까? 로그 만 있습니까?
inor

클래스 내에서 로거를 생성해도 문제가 발생하지 않습니다. 클래스가 자체 로거를 생성하기 때문에 UT하기 어려운 간단한 예제를 보여줄 수 있습니까?
inor

1
확실한. 이메일을 보내는 로거는 어떻습니까? 테스트를 실행할 때마다 그렇게하고 싶지는 않습니다. 또한 부작용을 어떻게 주장합니까?
Wayne Allen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.