Logger.getLogger (MyClass.class)가 log4j 로거를 초기화하는 가장 좋은 방법입니까?


13

이 Mkyong 튜토리얼은 로거를 다음과 같이 제안합니다.

@Controller
public class WelcomeController {

    private static final Logger logger = Logger.getLogger(WelcomeController.class);

   // etc

}

아마도 당신이 사용하는 다른 모든 클래스, 아마도 로거가있는 것은 로거를 같은 방식으로 초기화합니다.

내 질문은-이것이 최선의 방법입니까? 반복되는 것 같습니다.


2
이것에 대한 자세한 정보는 무엇입니까 (Java의 구문을 제외하고) ?. 로거를 보유 할 변수를 작성하고 로거 getLogger()의 이름 을 알려야 합니다.
kdgregory

2
@ kdgregory 내가 모든 수업에서 똑같은 일을하고 있다는 사실.
dwjohnston 2016 년


3
이전하기에는 너무 오래되었지만이 질문은 여기서는 주제가 아니며 StackOverflow에 더 적합합니다.
Andres F.

1
@AndresF. 기술적 인 문제보다는 코드 스타일 / 디자인 패턴에 대한 질문이기 때문에 여기에 넣은 것 같습니다.
dwjohnston

답변:


16

귀하의 의견에 따르면 "자세한 내용"은 모든 클래스에서이 코드 줄을 반복해야한다는 의미입니다. 첫 번째 답변은 큰 그림에서 모든 클래스에 두 줄의 코드 (변수 정의와 import 문)를 추가하는 것이 그렇게 큰 문제는 아니라는 것입니다. 특히 동작이있는 클래스에 추가하기 만하면되므로 로깅이 필요합니다. 즉, 사용중인 특정 코드 줄은 복사 붙여 넣기 오류가 발생하기 쉽습니다 (나중에 자세히 설명).

그러나 대안을 원하기 때문에 몇 가지 대안을 사용할 수 있습니다.

전체 앱에 단일 로거 사용

보고하는 클래스에 신경 쓰지 않거나 필요한 모든 컨텍스트를 메시지에 넣을 의사가있는 경우 간단한 싱글 톤 로거가 작업을 수행합니다.

LoggerSingleton.getInstance().debug("MyController is running")

제 생각에, 로깅 프레임 워크의 가장 큰 장점 중 하나는 로그 메시지를 다른 대상으로 보내는 경우에만 별도의 로거 인스턴스가 제공하는 컨텍스트를 갖는 것입니다. 한 줄의 코드를 저장하기 위해 포기하지 않을 것입니다 (여전히 가져 오기가 필요합니다).

또한 이는 사용 시점의 세부 정보를 증가시켜 더 많은 키 입력으로 이어집니다.

사용 시점에서 로거 작성

변수를 제거하기 때문에 이것을 버리고 있습니다. 나는 그것에 대해 언급 할 필요가 없다고 생각합니다. 로거 인스턴스를 얻는 데 선호하는 기술을 보여 주지만.

Logger.getLogger(getClass()).debug("blah blah blah");

빈 포스트 프로세서를 사용하여 로거 주입

예제에서는 Spring을 사용하고 Spring을 사용하면 Bean 초기화 코드에 연결할 수 있습니다. Bean에서 logger멤버 변수 를 검사하고 Logger인스턴스를 찾으면 인스턴스를 작성하는 포스트 프로세서를 작성할 수 있습니다 .

이러한 포스트 프로세서는 수십 줄의 코드에 불과하지만 응용 프로그램의 또 다른 부분이며 따라서 잠재적 인 버그의 또 다른 원인입니다. 나는 가능한 한 적은 것을 선호합니다.

믹스 인 사용

스칼라와 그루비는 특성을 제공하여 행동을 캡슐화 할 수 있습니다. 전형적인 스칼라 패턴은 Logging특성 을 생성 한 다음 로깅이 필요한 클래스에 추가하는 것입니다.

class MyController with Logging

불행히도, 이것은 언어를 바꿔야한다는 것을 의미합니다. Java 8을 사용하지 않는 경우 Logging"기본 방법"으로 인터페이스를 작성할 수 있습니다 .

public interface Logging {
    default Logger getLogger() {
        return Logger.getLogger(getClass());
    } 
}

이제 수업 코드 내에서 간단하게 사용할 수 있습니다.

getLogger().debug("blah blah blah");

쉽지만 여기에는 몇 가지 단점이 있습니다. 우선, 모든 인터페이스 메소드가 공용이기 때문에이를 사용하는 모든 클래스의 인터페이스를 오염시킵니다. Spring이 인스턴스화하고 주입 한 클래스, 특히 인터페이스 / 구현 분리를 따르는 경우에만 사용하면 나쁘지 않을 것입니다.

더 큰 문제는 모든 호출에서 실제 로거 인스턴스를 찾아야한다는 것입니다. 빠르지 만 불필요합니다.

그리고 여전히 수입 명세서가 필요합니다.

로거를 수퍼 클래스로 이동

반복하겠습니다 : 반복적 인 로거 정의를 자세하게 찾을 수는 없지만,이를 제거하는 가장 좋은 방법이라고 생각합니다.

public abstract class AbstractController {
    protected Logger logger = Logger.getLogger(getClass());
}

이제 컨트롤러 클래스가에서 상속되며 변수에 AbstractController액세스 할 수 logger있습니다. 당신은 넣어야 할 것을 기억 @Controller콘크리트 클래스에 주석을.

어떤 사람들은 이것이 상속의 왜곡을 발견 할 것입니다. 나는 그 AbstractController대신 수업의 이름을 정함으로써 그들을 화나게하려고 노력했다 AbstractProjectClass. 관계 있는지 여부를 스스로 결정할 수 있습니다 .

다른 사람들은 정적 변수가 아닌 인스턴스 변수 사용에 반대합니다. 클래스 이름을 명시 적으로 참조해야하기 때문에 IMO 정적 로거는 복사 붙여 넣기 오류가 발생하기 쉽습니다. getClass()로거가 항상 올바른지 확인하십시오.


상속 클래스의 getClass ()에 대해 조심해야한다고 생각합니다. MethodHandles.lookup (). lookupClass ()는 jdk 7 이후에 더 좋습니다
yuxh

@luxh-당신은 그것에 대한 설명이 있습니까?
kdgregory


@yuxh-그 질문에 MethodHandles의 유일한 언급 (연결 된 답변에 없었습니다)은 설명을 요구하는 주석이있는 유사한 지원되지 않는 주장입니다. 당신이 있습니까 권위 주장에 대한 지원 MethodHandles.lookup().lookupClass()보다 낫다을 Object.getClass()?
kdgregory

MethodHandles.lookup().lookupClass()정적 변수에 사용할 수있는 오류를 복사 - 붙여 넣기하는 경향이 없으며 빠른 : stackoverflow.com/a/47112323/898747는 이 그래서 내가 매우 정적 무관 내 로거처럼 여분의 인포을 의미 않지만, 적어도 가치 (A)에서 언급 :)
FableBlaze

0

@kdgregory가 제공하는 답변을 확장하기 위해 Groovy는 클래스에서 AST 변환을 수행하는 주석으로 즉시 @Slf4j( groovy.util.logging.Slf4j)를 제공 하여 log지정하지 않은 경우 기본적으로 변수 이름을 가정하는 로거로 고정합니다 .

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