Java에서 로거를 선언하는 것이 가장 좋은 방법은 static final무엇입니까?
private static final Logger S_LOGGER
Java에서 로거를 선언하는 것이 가장 좋은 방법은 static final무엇입니까?
private static final Logger S_LOGGER
답변:
private-다른 클래스가 귀하의 로거를 납치 할 수 없도록static -클래스 당 하나의 로거 인스턴스 만 있으므로 로거를 직렬화하려는 시도를 피할 수 있습니다.final -수업 기간 동안 로거를 변경할 필요가 없습니다.또한 log가능한 한 단순하면서도 설명적인 이름 을 선호합니다 .
편집 : 그러나이 규칙에는 흥미로운 예외가 있습니다.
protected final Logger log = LoggerFactory.getLogger(getClass());
반대로 :
private static final Logger log = LoggerFactory.getLogger(Foo.class);
전자를 사용하면 상속 계층 전체의 모든 클래스에서 동일한 로거 이름 (실제 클래스의 이름)을 사용할 수 있습니다. 따라서 Bar확장 Foo하면 Bar로거에 모두 기록됩니다 . 더 직관적 인 사람들도 있습니다.
log코드를 산란하는 것보다 작성하기 쉽고 이름 을 읽는 것이 더 좋습니다 LOG. 개발자의 문제. 팀 계약.
이 블로그 게시물 : Java 정적 로거 제거를 확인하십시오 . 이것은 jcabi-log 와 함께 slf4j 를 사용하는 방법입니다 .
import com.jcabi.log.Logger;
class Foo {
void save(File f) {
Logger.info(this, "file %s saved successfully", f);
}
}
정적 잡음을 더 이상 사용하지 마십시오.
static즉, 클래스 인스턴스 당 하나의 로거가 아니라 클래스 당 하나의 로거 만 작성 합니다. 로거는 클래스에 따라 달라지기 때문에 일반적으로 원하는 것입니다.
finallogger변수 의 값을 변경하지 않을 것임을 의미 합니다. 거의 항상 모든 로그 메시지를 (한 클래스에서) 동일한 로거로 던지기 때문입니다. 드문 경우이지만 클래스가 일부 메시지를 다른 로거에 보내려고 할 때도 widgetDetailLogger정적 변수의 값을 즉시 변경하지 않고 다른 로거 변수 (예 :)를 작성하는 것이 훨씬 더 명확합니다 .
일반적으로 클래스 이름을 사용하여 기록하도록 로거를 초기화합니다. 즉, 정적이 아닌 경우 클래스의 인스턴스가 많은 각 인스턴스 (메모리 공간 부족)가 발생하지만이 로거는 모두 동일한 구성을 공유하고 정확히 동일하게 작동합니다. 그것이 static비트 뒤에있는 이유 입니다. 또한 각각 Logger클래스 이름으로 초기화 되므로 하위 클래스와의 충돌을 막기 위해 private상속 할 수 없도록 선언합니다 . 은 final당신이 일반적으로 변경하지 않는 것이 포인트에서 유래 Logger하여 (이 경우는 아무도 그것을 변경할 수 있도록하는 것을 최종 확인하는 것이 합리적이다 - 그래서 한 번 당신이 "다시는 구성하지"결코하여 초기화 - 실행 중 실수 또는 그렇지 않으면). 물론 당신이 사용하려는 경우Logger다른 방법 으로 사용 하지 않아도 될 수도 static final있지만 앱의 80 %가 위에서 설명한대로 로깅을 사용한다고 생각합니다.
이 질문에 대답하려면 "정적"과 "최종"이 무엇인지 스스로에게 물어야합니다.
Logger의 경우 (Log4J Logger 클래스에 대해 이야기한다고 가정) 클래스별로 범주를 원합니다. 이것은 한 번만 할당하고 클래스 당 하나 이상의 인스턴스가 필요하지 않다는 사실로 이어질 것입니다. 아마도 한 클래스의 Logger 객체를 다른 클래스에 노출시킬 이유가 없기 때문에 비공개로 만들고 일부 OO 원칙을 따르지 않는 이유는 무엇입니까?
또한 컴파일러는 그 이점을 활용할 수 있습니다. 따라서 코드가 약간 더 잘 수행됩니다. :)
이는 일반적으로 객체의 모든 인스턴스에서 공유 할 수있는 기능의 종류이기 때문입니다. 같은 클래스의 두 인스턴스에 대해 서로 다른 로거를 갖는 것은 의미가 없습니다 (90 %의 시간).
그러나 때때로 로거 클래스가 싱글 톤으로 선언되거나 단순히 정적 함수를 제공하여 물건을 기록하는 것을 볼 수도 있습니다.
이 코드는 취약하지만 Java7 이후 Logger lgr = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
에는 정적 로거 대신 사용할 수 있습니다 .
This is code is vulnerable당신은 조금 대답을 명확히 할 수 있습니까?
이상적으로 Logger는 Sonar를 제공하지 않고 호환 코드를 제공하기 위해 Java 7까지 다음과 같아야합니다. private : 부모 클래스 외부에서는 액세스 할 수 없습니다. 다른 클래스가 무언가를 기록해야하는 경우 자체 로거를 인스턴스화해야합니다. static : 클래스의 인스턴스 (객체)에 의존하지 않습니다. 무엇인가를 로깅 할 때, 물론 상황 정보가 메시지에 제공 될 수 있지만 각 객체와 함께 로거가 생성되지 않도록하여 메모리 사용량이 많지 않도록 로거를 클래스 레벨에서 작성해야합니다. final : 수업 당 한 번만 작성하십시오.
다른 답변에 주어진 이유 외에도 내가 겪었던 한 가지 이유는 내 로거가 정적이거나 최종적이지 않은 것입니다.
...
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());
...
실제로 정적 로거는 정적 컨텍스트에서 작동해야하므로 "유해"할 수 있습니다. 동적 환경이있는 경우 예. OSGi는 비 정적 로거를 사용하는 데 도움이 될 수 있습니다. 일부 로깅 구현은 내부적으로 로거 캐싱 (AFAIK 이상 log4j)을 수행하므로 성능 영향은 무시할 수 있습니다.
정적 로거의 한 가지 단점은 다음과 같습니다. 가비지 수집 (클래스가 한 번만 사용되는 경우 (예 : 초기화 중 로거는 계속 유지됨))
자세한 내용은 다음을 확인하십시오.
또한보십시오:
인터넷에서 로거를 정적으로 만드는지에 관한 정보에 따르면, 가장 좋은 방법은 사용 사례에 따라 사용하는 것입니다.
두 가지 주요 주장이 있습니다.
1) 정적 상태로 만들면 가비지 수집되지 않습니다 (메모리 사용 및 성능).
2) 정적이 아닌 경우 각 클래스 인스턴스에 대해 생성됩니다 (메모리 사용량)
따라서 싱글 톤에 대한 로거를 작성할 때 정적 로거로 만들 필요가 없습니다. 하나의 인스턴스 만 있으므로 로거는 하나만 있기 때문입니다.
반면에 모델 또는 엔티티 클래스에 대한 로거를 작성하는 경우 중복 된 로거를 작성하지 않도록 정적으로 만들어야합니다.