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


110

상태에 대한 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));
        }
    }
}

10
INFO 이상에 대해 콘솔에 메시지가 두 번 인쇄되는 것 같습니다. 먼저 익명 로거에 의해 다음 부모에 의해 기본적으로 ConsoleHandler가 INFO로 설정된 전역 로거에 의해 인쇄됩니다. 전역 로거를 비활성화하려면 다음 코드 줄을 추가해야합니다. logger.setUseParentHandlers (false);
mins

복식에 대한 분 코멘트를 확인하고 싶습니다. .setUseParentHandlers (false)를 사용하지 않으면 두 개의 출력을 얻을 수 있습니다.
xpagesbeast

답변:


124

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

당신은 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);

2
감사. 그게 속임수였습니다. 내가 처음에 왜 그렇게 혼란 스러웠는지 이제 깨달았다. 이전에 로깅 수준으로 작업 한 적이 있었지만 당시의 구현은 단순히 모든 로깅 된 메시지를 Handler.
Andrew Thompson

3
천만에요. 그리고 네, 디자인은 하나가 단순히 파일에 문자열을 덤프 로거를 작성 한 경우 등 콘솔, 당신에 도착 않습니다
Vineet 레이놀즈

7
그리고 글로벌 JRE 라이브러리에서 logging.properties를 변경하는 것이 관리 가능합니까?
James Anderson

2
로거 자체의 수준은 처리기 수준보다 덜 제한적이어야합니다. 로깅하기 전에 Java는 로거와 핸들러 사이의 최대 레벨을 확인합니다. 따라서 handler.setLevel (Level.FINER); 기본 로거 레벨이 Level.INFO이기 때문에 아무것도 표시되지 않습니다. FINER, FINEST 또는 ALL로 설정해야합니다. logger.setLevel (Level.ALL);
Jeff_Alieffson

기본 환경에서 익명 및 명명 된 로거를 사용하는 경우에도 Logger.getGlobal().getParent().getHandlers()[0].setLevel(Level.FINER);
이것이 한 줄로

27

이유

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 구성 요소와 같은 핵심 라이브러리의 메시지를 볼 수 있습니다. 이 경우 당신은 설정할 수 있습니다 필터 프로그램에서하지 메시지를 필터링 할 루트 로거에 있습니다.


applog.setUseParentHandlers (false)이 코드는 저에게 도움이됩니다. 정말 감사합니다.
aolphn

4

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

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


이것은 답변이 아니라 설명입니다.
hfontanez

4

@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이 아닌) 수준 값을 사용하여 가장 가까운 조상으로부터 수준을 상속해야 함을 의미합니다.


0

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


0

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

    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");

0

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

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