[java] Level.FINE 로깅 메시지가 표시되지 않는 이유는 무엇입니까?

상태에 대한 JavaDocsjava.util.logging.Level :


내림차순의 레벨은 다음과 같습니다.

  • SEVERE (가장 높은 값)
  • WARNING
  • INFO
  • CONFIG
  • FINE
  • FINER
  • FINEST (가장 낮은 값)

출처

import java.util.logging.*;

class LoggingLevelsBlunder {

    public static void main(String[] args) {
        Logger logger = Logger.getAnonymousLogger();
        logger.setLevel(Level.FINER);
        System.out.println("Logging level is: " + logger.getLevel());
        for (int ii=0; ii<3; ii++) {
            logger.log(Level.FINE, ii + " " + (ii*ii));
            logger.log(Level.INFO, ii + " " + (ii*ii));
        }
    }
}

산출

Logging level is: FINER
Jun 11, 2011 9:39:23 PM LoggingLevelsBlunder main
INFO: 0 0
Jun 11, 2011 9:39:24 PM LoggingLevelsBlunder main
INFO: 1 1
Jun 11, 2011 9:39:24 PM LoggingLevelsBlunder main
INFO: 2 4
Press any key to continue . . .

문제 설명

내 예는 설정 LevelFINER내가 각 루프에 대한이 메시지를 볼 것으로 예상 그래서. 대신 각 루프에 대해 단일 메시지가 표시됩니다 ( Level.FINE메시지가 없음).

질문

FINE( FINER또는 FINEST) 출력 을 보려면 무엇을 변경해야 합니까?

업데이트 (솔루션)

Vineet Reynolds의 답변 덕분 에이 버전은 내 기대대로 작동합니다. 3 개의 INFO메시지와 3 개의 메시지를 표시 FINE합니다.

import java.util.logging.*;

class LoggingLevelsBlunder {

    public static void main(String[] args) {
        Logger logger = Logger.getAnonymousLogger();
        // LOG this level to the log
        logger.setLevel(Level.FINER);

        ConsoleHandler handler = new ConsoleHandler();
        // PUBLISH this level
        handler.setLevel(Level.FINER);
        logger.addHandler(handler);

        System.out.println("Logging level is: " + logger.getLevel());
        for (int ii=0; ii<3; ii++) {
            logger.log(Level.FINE, ii + " " + (ii*ii));
            logger.log(Level.INFO, ii + " " + (ii*ii));
        }
    }
}



답변

로거는 메시지 만 기록합니다. 즉, 로그 기록 (또는 기록 요청)을 생성합니다. 처리기가 처리하는 대상에 메시지를 게시하지 않습니다. 로거 수준을 설정하면 해당 수준 이상과 일치하는 로그 레코드 만 생성 됩니다.

당신은 ConsoleHandler(당신의 출력이 System.err 또는 파일 인 곳을 추론 할 수는 없지만 그것이 전자라고 가정합니다)를 사용할 수 있습니다. 이는 기본적으로 수준의 로그 레코드를 게시합니다 Level.INFO. Level.FINER원하는 결과를 위해 레벨 이상의 로그 레코드를 게시하려면이 핸들러를 구성해야합니다 .

기본 디자인을 이해하려면 Java 로깅 개요 가이드를 읽는 것이 좋습니다 . 이 가이드는 로거와 핸들러 개념의 차이점을 다룹니다.

핸들러 레벨 편집

1. 구성 파일 사용

java.util.logging 속성 파일 (기본적으로의 logging.properties파일 JRE_HOME/lib)을 수정하여 ConsoleHandler의 기본 수준을 변경할 수 있습니다.

java.util.logging.ConsoleHandler.level = FINER

2. 런타임에 핸들러 생성

글로벌 구성을 대체 할 수 있으므로 권장되지 않습니다. 코드베이스 전체에서 이것을 사용하면 관리 할 수없는 로거 구성이 발생할 수 있습니다.

Handler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.FINER);
Logger.getAnonymousLogger().addHandler(consoleHandler);


답변

이유

java.util.logging에는 기본값 인 루트 로거와 기본값 인 Level.INFOConsoleHandler가 첨부되어 있습니다 Level.INFO.
FINE이보다 낮으므로 INFO기본적으로 고급 메시지가 표시되지 않습니다.


해결책 1

예를 들어 패키지 이름에서 전체 애플리케이션에 대한 로거를 생성하거나를 사용 Logger.getGlobal()하고 자체 ConsoleLogger를 여기에 연결합니다. 그런 다음 루트 로거에게 종료를 요청하거나 (상위 메시지의 중복 출력을 방지하기 위해) 로그 를 루트로 전달하지 않도록 로거에 요청하십시오 .

public static final Logger applog = Logger.getGlobal();
...

// Create and set handler
Handler systemOut = new ConsoleHandler();
systemOut.setLevel( Level.ALL );
applog.addHandler( systemOut );
applog.setLevel( Level.ALL );

// Prevent logs from processed by default Console handler.
applog.setUseParentHandlers( false ); // Solution 1
Logger.getLogger("").setLevel( Level.OFF ); // Solution 2

해결 방법 2

또는 루트 로거의 막대를 낮출 수 있습니다.

코드로 설정할 수 있습니다.

Logger rootLog = Logger.getLogger("");
rootLog.setLevel( Level.FINE );
rootLog.getHandlers()[0].setLevel( Level.FINE ); // Default console handler

또는 로깅 구성 파일을 사용하는 경우 :

.level = FINE
java.util.logging.ConsoleHandler.level = FINE

전역 수준을 낮추면 일부 Swing 또는 JavaFX 구성 요소와 같은 핵심 라이브러리의 메시지를 볼 수 있습니다. 이 경우 당신은 설정할 수 있습니다 필터 프로그램에서하지 메시지를 필터링 할 루트 로거에 있습니다.


답변

내 자바 로깅이 작동하지 않는 이유

로그인이 예상대로 작동하지 않는 이유를 파악하는 데 도움이되는 jar 파일을 제공합니다. 어떤 로거와 핸들러가 설치되었는지, 어떤 레벨이 설정되었는지, 로깅 계층 구조에서 어느 레벨에 있는지에 대한 완전한 덤프를 제공합니다.


답변

@Sheepy에서 언급했듯이 작동하지 않는 이유 java.util.logging.Logger는 기본값 인 루트 로거가 Level.INFO있고 ConsoleHandler해당 루트 로거에 첨부 된 파일도 기본값 인 Level.INFO. 따라서 참조하기 위해 FINE( FINER또는 FINEST) 출력을, 루트 로거의 기본 값을 설정해야하고는 ConsoleHandler하기 Level.FINE로 다음과 같습니다 :

Logger.getLogger("").setLevel(Level.FINE);
Logger.getLogger("").getHandlers()[0].setLevel(Level.FINE);

업데이트 문제 (솔루션)

@mins가 언급했듯이 콘솔에 메시지가 두 번 인쇄됩니다 INFO. 먼저 익명 로거에 의해 다음 상위 로거 가 기본적으로 ConsoleHandler설정되어 있는 루트 로거 에 INFO의해 인쇄됩니다. 루트 로거를 비활성화하려면 다음 코드 줄을 추가해야합니다.logger.setUseParentHandlers(false);

@Sheepy가 언급 한 루트 로거의 기본 콘솔 핸들러에서 로그가 처리되는 것을 방지하는 다른 방법이 있습니다. 예 :

Logger.getLogger("").getHandlers()[0].setLevel( Level.OFF );

그러나 Logger.getLogger("").setLevel( Level.OFF );루트 로거에 직접 전달 된 메시지 만 차단하고 자식 로거에서 온 메시지가 아니므로 작동하지 않습니다. Logger Hierarchy작동 방식을 설명하기 위해 다음 다이어그램을 그립니다.

여기에 이미지 설명 입력

public void setLevel(Level newLevel)이 로거가 기록 할 메시지 수준을 지정하는 로그 수준을 설정합니다. 이 값보다 낮은 메시지 수준은 삭제됩니다. 레벨 값 Level.OFF를 사용하여 로깅을 끌 수 있습니다. 새 수준이 null이면이 노드가 특정 (null이 아닌) 수준 값을 사용하여 가장 가까운 조상으로부터 수준을 상속해야 함을 의미합니다.


답변

내 실제 문제를 발견했지만 어떤 답변에도 언급되지 않았습니다. 일부 단위 테스트로 인해 로깅 초기화 코드가 동일한 테스트 스위트 내에서 여러 번 실행되어 이후 테스트에서 로깅이 엉망이되었습니다.


답변

다른 변형을 시도했습니다. 이것은 적절할 수 있습니다.

    Logger logger = Logger.getLogger(MyClass.class.getName());
    Level level = Level.ALL;
    for(Handler h : java.util.logging.Logger.getLogger("").getHandlers())
        h.setLevel(level);
    logger.setLevel(level);
// this must be shown
    logger.fine("fine");
    logger.info("info");


답변

이 솔루션은 유지 관리 및 변경 설계와 관련하여 나에게 더 잘 보입니다.

  1. jar 파일에 포함 할 리소스 프로젝트 폴더에 포함하는 로깅 속성 파일을 만듭니다.

    # Logging
    handlers = java.util.logging.ConsoleHandler
    .level = ALL
    
    # Console Logging
    java.util.logging.ConsoleHandler.level = ALL
  2. 코드에서 속성 파일을로드합니다.

    public static java.net.URL retrieveURLOfJarResource(String resourceName) {
       return Thread.currentThread().getContextClassLoader().getResource(resourceName);
    }
    
    public synchronized void initializeLogger() {
       try (InputStream is = retrieveURLOfJarResource("logging.properties").openStream()) {
          LogManager.getLogManager().readConfiguration(is);
       } catch (IOException e) {
          // ...
       }
    }