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


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.