왜 우리는 Loggers를 static final로 선언합니까?


131

Java에서 로거를 선언하는 것이 가장 좋은 방법은 static final무엇입니까?

private static final Logger S_LOGGER

답변:


209
  • private-다른 클래스가 귀하의 로거를 납치 할 수 없도록
  • static -클래스 당 하나의 로거 인스턴스 만 있으므로 로거를 직렬화하려는 시도를 피할 수 있습니다.
  • final -수업 기간 동안 로거를 변경할 필요가 없습니다.

또한 log가능한 한 단순하면서도 설명적인 이름 을 선호합니다 .

편집 : 그러나이 규칙에는 흥미로운 예외가 있습니다.

protected final Logger log = LoggerFactory.getLogger(getClass());

반대로 :

private static final Logger log = LoggerFactory.getLogger(Foo.class);

전자를 사용하면 상속 계층 전체의 모든 클래스에서 동일한 로거 이름 (실제 클래스의 이름)을 사용할 수 있습니다. 따라서 Bar확장 Foo하면 Bar로거에 모두 기록됩니다 . 더 직관적 인 사람들도 있습니다.


36
정적이고 최종적이라면 오히려 LOG (대문자)
zacheusz

39
@zacheusz , 그게 요점입니다. 어떤 사람들은 종교적으로 Java 명명 규칙을 따르지 만 (그것에 아무런 문제가 없습니다), 나는 log코드를 산란하는 것보다 작성하기 쉽고 이름 을 읽는 것이 더 좋습니다 LOG. 개발자의 문제. 팀 계약.
Tomasz Nurkiewicz

27
로거를 정적 및 최종으로 선언하는 것이 더 이상 권장되지는 않습니다. slf4j.org/faq.html#declared_staticwiki.apache.org/commons/Logging/FrequentlyAskedQuestions 섹션 Log 참조를 정적으로 선언해야합니까?
Matthew Farwell

6
@zacheusz 대문자로 된 필드 이름은 상수에 사용됩니다. 로거는 일정하지 않습니다. http://stackoverflow.com/questions/1417190/should-a-static-final-logger-be-declared-in-upper-case
michal.kreuzman

2
@zacheusz 모든 정적 최종 속성이 대문자가 아닌 것은 아닙니다 : stackoverflow.com/questions/1417190/…
bsmk

15

이 블로그 게시물 : Java 정적 로거 제거를 확인하십시오 . 이것은 jcabi-log 와 함께 slf4j 를 사용하는 방법입니다 .

import com.jcabi.log.Logger;
class Foo {
  void save(File f) {
    Logger.info(this, "file %s saved successfully", f);
  }
}

정적 잡음을 더 이상 사용하지 마십시오.


흥미로운 대안이며 확실히 깨끗합니다. 개별 클래스 로거와 비교하여 어떻게 확장되는지 궁금합니다.
Ross

12
매번 더 긴 Logger .. (this, ...)를 쓰십시오. 아냐
Mikhail Boyarsky

관련 블로그 게시물의 첫 번째 의견은 정적 메소드의 악의적 인 측면을 나타냅니다. :) 개인 최종 로거를 사용하는 것이 가장 좋습니다.
Bahadir Tasdemir

5

static즉, 클래스 인스턴스 당 하나의 로거가 아니라 클래스 당 하나의 로거 만 작성 합니다. 로거는 클래스에 따라 달라지기 때문에 일반적으로 원하는 것입니다.

finallogger변수 의 값을 변경하지 않을 것임을 의미 합니다. 거의 항상 모든 로그 메시지를 (한 클래스에서) 동일한 로거로 던지기 때문입니다. 드문 경우이지만 클래스가 일부 메시지를 다른 로거에 보내려고 할 때도 widgetDetailLogger정적 변수의 값을 즉시 변경하지 않고 다른 로거 변수 (예 :)를 작성하는 것이 훨씬 더 명확합니다 .


4

필드 값을 언제 변경 하시겠습니까?

당신이 결코 필드의 마지막을, 값을 변경 않을 경우 것은 만드는 명백한 값을 변경하지 않을거야.


1
많은 경우에 final이라는 단어를 추가하지 않으면 분명합니다.이 경우 일종의 정크가됩니다.
Dima

2
@Dima : 그럼 난 아직도 내가 경우 컴파일러는 여전히 오류가 발생합니다 것을 감사드립니다 않습니다 ... 실수로 이러한 경우 값을 변경하려고
존 소총

3

일반적으로 클래스 이름을 사용하여 기록하도록 로거를 초기화합니다. 즉, 정적이 아닌 경우 클래스의 인스턴스가 많은 각 인스턴스 (메모리 공간 부족)가 발생하지만이 로거는 모두 동일한 구성을 공유하고 정확히 동일하게 작동합니다. 그것이 static비트 뒤에있는 이유 입니다. 또한 각각 Logger클래스 이름으로 초기화 되므로 하위 클래스와의 충돌을 막기 위해 private상속 할 수 없도록 선언합니다 . 은 final당신이 일반적으로 변경하지 않는 것이 포인트에서 유래 Logger하여 (이 경우는 아무도 그것을 변경할 수 있도록하는 것을 최종 확인하는 것이 합리적이다 - 그래서 한 번 당신이 "다시는 구성하지"결코하여 초기화 - 실행 중 실수 또는 그렇지 않으면). 물론 당신이 사용하려는 경우Logger다른 방법 으로 사용 하지 않아도 될 수도 static final있지만 앱의 80 %가 위에서 설명한대로 로깅을 사용한다고 생각합니다.


3

이 질문에 대답하려면 "정적"과 "최종"이 무엇인지 스스로에게 물어야합니다.

Logger의 경우 (Log4J Logger 클래스에 대해 이야기한다고 가정) 클래스별로 범주를 원합니다. 이것은 한 번만 할당하고 클래스 당 하나 이상의 인스턴스가 필요하지 않다는 사실로 이어질 것입니다. 아마도 한 클래스의 Logger 객체를 다른 클래스에 노출시킬 이유가 없기 때문에 비공개로 만들고 일부 OO 원칙을 따르지 않는 이유는 무엇입니까?

또한 컴파일러는 그 이점을 활용할 수 있습니다. 따라서 코드가 약간 더 잘 수행됩니다. :)


2

이는 일반적으로 객체의 모든 인스턴스에서 공유 할 수있는 기능의 종류이기 때문입니다. 같은 클래스의 두 인스턴스에 대해 서로 다른 로거를 갖는 것은 의미가 없습니다 (90 %의 시간).

그러나 때때로 로거 클래스가 싱글 톤으로 선언되거나 단순히 정적 함수를 제공하여 물건을 기록하는 것을 볼 수도 있습니다.


2

이 코드는 취약하지만 Java7 이후 Logger lgr = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); 에는 정적 로거 대신 사용할 수 있습니다 .


This is code is vulnerable당신은 조금 대답을 명확히 할 수 있습니까?
Dmitry Zagorulkin

1

대부분의 경우 참조를 변경하지 않으며 final수정자가이를 표시합니다. 각 클래스 인스턴스마다 별도의 인스턴스가 필요하지 않습니다 static. 그리고 무엇보다도 이것은 성능을위한 것입니다. 최적화 (최종) 및 메모리 절약 (정적)이 가능합니다.


1

이상적으로 Logger는 Sonar를 제공하지 않고 호환 코드를 제공하기 위해 Java 7까지 다음과 같아야합니다. private : 부모 클래스 외부에서는 액세스 할 수 없습니다. 다른 클래스가 무언가를 기록해야하는 경우 자체 로거를 인스턴스화해야합니다. static : 클래스의 인스턴스 (객체)에 의존하지 않습니다. 무엇인가를 로깅 할 때, 물론 상황 정보가 메시지에 제공 될 수 있지만 각 객체와 함께 로거가 생성되지 않도록하여 메모리 사용량이 많지 않도록 로거를 클래스 레벨에서 작성해야합니다. final : 수업 당 한 번만 작성하십시오.


0

다른 답변에 주어진 이유 외에도 내가 겪었던 한 가지 이유는 내 로거가 정적이거나 최종적이지 않은 것입니다.

...
public Logger logger = LoggerFactory.getLogger(DataSummary.class);

public String toJson() {
  GsonBuilder gsonBuilder = new GsonBuilder();   
  return gsonBuilder.create().toJsonTree(this).toString();
}
...

어떤 경우에는 (Gson 라이브러리를 사용했을 때) stackoverflow 예외가 발생합니다. 내 구체적인 상황은 비 정적 최종 로거가 포함 된 클래스를 인스턴스화하는 것이 었습니다. 그런 다음 GsonBuilder를 호출 한 toJson 메소드를 호출하십시오.

...
DataSummary ds = new DataSummary(data);    
System.out.println(ds.toJson());
...

0

실제로 정적 로거는 정적 컨텍스트에서 작동해야하므로 "유해"할 수 있습니다. 동적 환경이있는 경우 예. OSGi는 비 정적 로거를 사용하는 데 도움이 될 수 있습니다. 일부 로깅 구현은 내부적으로 로거 캐싱 (AFAIK 이상 log4j)을 수행하므로 성능 영향은 무시할 수 있습니다.

정적 로거의 한 가지 단점은 다음과 같습니다. 가비지 수집 (클래스가 한 번만 사용되는 경우 (예 : 초기화 중 로거는 계속 유지됨))

자세한 내용은 다음을 확인하십시오.

또한보십시오:


0

인터넷에서 로거를 정적으로 만드는지에 관한 정보에 따르면, 가장 좋은 방법은 사용 사례에 따라 사용하는 것입니다.

두 가지 주요 주장이 있습니다.

1) 정적 상태로 만들면 가비지 수집되지 않습니다 (메모리 사용 및 성능).

2) 정적이 아닌 경우 각 클래스 인스턴스에 대해 생성됩니다 (메모리 사용량)

따라서 싱글 톤에 대한 로거를 작성할 때 정적 로거로 만들 필요가 없습니다. 하나의 인스턴스 만 있으므로 로거는 하나만 있기 때문입니다.

반면에 모델 또는 엔티티 클래스에 대한 로거를 작성하는 경우 중복 된 로거를 작성하지 않도록 정적으로 만들어야합니다.


-1

내부 정적 클래스에는 여전히 정적 로거가 필요합니다.

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