Java.util.logging 우수 사례

다음은 JSR47 사용에 대한 우수 사례 모음입니다.
  1. 로거(logger)를 가져오기 위한 좋은 방법이 있습니까?
    각 클래스에서 다음 패턴을 사용하여 JSR47 로거를 확보할 수 있습니다.
    private static final String CLAZZ_NAME = MyClass.class.getName();
    private static final String PKG = MyClass.class.getPackage().getName();
    private static Logger _logger = Logger.getLogger(PKG);

    MyClass에 대해 사용자의 클래스 이름으로 대체하고 패키지의 리프 노드와 같은 이름을 가지고 있는 특성 파일이 있는지 확인하십시오.

    주: CLAZZ_NAME 정의는 로거(logger) 초기화에 필요하지 않지만 모든 logp() 로깅 및 추적 호출에 사용됩니다. 표시된 대로 설정해야 합니다.
    주: 이 패턴을 사용하는 경우 나중에 패키지 이름을 바꿀 때 주의해야 합니다.
  2. LogManager.getLogger("com.ibm.rcp.mypackage");를 사용하지 않는 이유는 무엇입니까?

    java.util.logging.LogManager.getLogger(String name)는 일치하는 이름을 가지고 있는 로거(이미 존재하는 경우)를 리턴합니다. 그렇지 않으면 널(null)을 리턴합니다. 사용자 클래스의 인스턴스가 생성될 때 제공된 로거가 존재할 것이라는 보장이 없습니다. 클래스 인스턴스화 순서가 판별되지 않기 때문입니다. 현재 존재해도 나중에 순서를 변경할 수 있습니다. 따라서 Logger가 리턴되도록 하려면 Logger 클래스에서 get 메소드를 사용해야 합니다. 로거(logger)를 가져오기 위해 LogManager 또는 Logger를 사용하는지 관계없이, 이름 지정된 로거의 하나 이하의 인스턴스가 지정된 시간에 VM 내에 존재합니다.

  3. 내 로거의 로그 레벨을 변경하려면 어떻게 합니까?
    LogManager<workspace>/.config/rcpinstall.properties 파일의 값을 통해 초기화됩니다. 여기에서 로거(logger) 레벨을 설정할 수 있습니다. 예를 들어, com.ibm.rcp.mypackage 패키지에서 사용자 코드에 해당되는 모든 로그 항목을 보려면 다음 문자열을 추가하십시오.
    com.ibm.rcp.mypackage.level=FINEST

    rcpinstall.properties의 기본값을 SEVERE로 변경하여 다른 JSR47 로거(logger)에서 SEVERE 레벨 메시지만 수신할 수 있습니다.

    Lotus® Expeditor의 OSGi 콘솔 기능을 사용하여 로깅 레벨을 동적으로 수정할 수도 있습니다. 이 작업을 수행하려면 –console을 실행에 추가하고 여기 설명된 대로 setlogrlevgetlogrlev 명령을 사용하십시오.

    setlogrlev osgi 콘솔 명령을 사용하여 JSR47 사용 Lotus Expeditor 컴포넌트를 추적할 수 있습니다. 이 명령의 도움말이 아래 표시됩니다.
    • setlogrlev <logger> (level) - 지정된 레벨로 로거를 설정하며 기본값으로 FINEST가 됩니다.
    • getlogrlev <logger> - 지정된 로거의 현재 레벨을 리턴합니다.
    다음 예제는 FINEST 레벨에서 com.ibm.rcp.core.internal.pd.manager 로거(logger) 추적을 사용하는 데 대해 자세히 설명합니다.
    osgi> setlogrlev com.ibm.rcp.core.internal.pd.manager
  4. 내 로그는 어디에 있습니까?

    시스템 로그는 <workspace>\logs\error-log-0.xml에 있습니다. 여기서 n은 숫자 0(현재 로그) 또는 1(마지막으로 실행된 로그)입니다.

    시스템 추적 파일은 <workspace>\logs\trace-log-0.xml에 있습니다. 여기서 n은 숫자 0(현재 로그) 또는 1(마지막으로 실행된 로그)입니다.

    로그 및 추적 파일에 대한 자세한 정보는 InfoCenter의 Lotus Expeditor 문제점 해결 지원 절의 클라이언트 데스크탑 문제점 해결 절을 참조하십시오.

  5. "보호받는 로깅"의 개념 및 필요한 이유는 무엇입니까?
    "보호받는 로깅"은 로그 명령문이 실행 이전에 출력을 초래하는지 확인하는 패턴입니다. 로거(logger) 자체에서 초기 검사를 수행하여 이 메시지가 로그 이벤트 핸들러로 전송되는지 확인하지만 로거 보호장치(guarder)에 도달하도록 모든 매개변수가 우선 해결되도록 하십시오. 일부 경우 매개변수를 해결하기 위해 복합 오퍼레이션 또는 String 조작이 필요할 수 있습니다. 이 경우, 로그 또는 추적을 호출하기 전에 Java™ 코드에 명시적 보호장치를 추가하도록 권장합니다. 다음 예제는 로그 메시지의 매개변수 해결의 일부로 복합 String 조작이 필요한 로깅 메시지를 보여줍니다.
                if(_logger.isLoggable(WARNING)){
                    _logger.logp(WARNING,CLAZZ_NAME, METHOD,
                         Nls.bind("warn.unable.to.get.preference",
                       new Object[]{pid,key}));
               }
    다음 코드 샘플은 단순 String 병합의“보호받는 로깅(guarded logging)”필요 여부를 나타냅니다.
       private boolean methodP(String param1, String param2) {         
    		logger.entering(CLAZZ_NAME,METHOD, param1 + "," + param2);
    }
    위의 샘플에서는 param1param2가 String이라고 가정합니다. 이 매개변수가 String 오브젝트가 아니며 복합 toString() 구현이 없는 경우 보호받는 로깅은 권장되지 않습니다.
    표 1. 보호받는 로깅 예제 및 설명
    예제 보호 필요 여부 이유
    _logger.logp( Level.SEVERE, CLAZZ_NAME, METHOD, NLS.bind( Messages.MessageKey, new Object[] { element[i].getContributor().getName() } ), exception ); 아니오 SEVERE 메시지는 항상 로깅됨
    _logger.logp( Level.WARNING, CLAZZ_NAME, METHOD, Messages.MessageKey2 ); 아니오 경고 메시지에 로깅하는 단순 호출
    _logger.logp( Level.INFO, CLAZZ_NAME, METHOD, NLS.bind( Messages.MessageKey, new Object[] { element[i].getContributor().getName(), createReportFromExtension( element[i] ) }, exception ) createReportFromExtension이 메시지에서 바꿀 오브젝트를 생성하는 중요한 작업을 수행해야 합니다.
    _logger.entering( CLAZZ_NAME, METHOD ) 아니오 _logger.entering는 레벨 검사를 수행하므로 코드 읽기가 쉬워집니다.

    String result = "something"

    ...

    _logger.exiting( CLAZZ_NAME, METHOD, result )

    아니오 _logger.exiting는 레벨 검사를 수행하므로 코드 읽기가 쉬워집니다.

    ...

    _logger.exiting( CLAZZ_NAME, METHOD, result )

    아니오 로깅 레벨을 사용하지 않으면 결과 오브젝트가 문자열로 변환되지 않습니다.

    SomeObject result = getFromSomeplace();

    ...

    _logger.exiting( CLAZZ_NAME, METHOD, result.toString() )

    toString() 오퍼레이션은 기존 메소드를 호출하기 전에 해결해야 하는 큰 문자열을 작성하므로 광범위한 문자열 오퍼레이션을 방지하도록 보호받는 검사를 수행하십시오.
    주: 매개변수에 toString() 메소드가 포함되지 않은 경우, 결과가 exiting() 서명과 일치하며 java.util.loggin이 제공하는 내장된 보호로 진행하므로 이 호출은 보호가 필요하지 않습니다.
  6. 각각의 로깅 레벨 사용에 대한 가이드라인은 무엇입니까?

    INFO

    수행: 컴포넌트의 정상 오퍼레이션을 표시하고 다른 코드 세그먼트에서 발생할 수 있는 문제점을 해결하는 데 유용하게 될 이벤트의 경우 INFO를 사용하십시오. 예를 들어, 설치 오퍼레이션의 완료를 확인한 후에는 실행기로부터 다음 메시지가 로깅됩니다.
    Done with install operations

    수행 금지: 디버그 정보나 프로그램 실행 추적에 대해, 잠재적으로 자주 반복되는 이벤트에서, 또는 관련된 이벤트의 문제점 원인을 판별할 때 유용하지 않을 경우 단지 이벤트를 확인하기 위해 INFO를 사용하지 마십시오.

    WARNING

    수행: 불리하게 정상 오퍼레이션에 영향을 줄 문제점이 발생했지만 대부분의 오퍼레이션이 계속되도록 할 경우에 WARNING을 사용하십시오. 좋은 예제는 프로비저닝으로부터의 다음 메시지입니다.
    Failed to retrieve page file for URL EXPEDITOR.png.

    수행 금지: 문제점으로 인해 기능을 완전히 또는 심각하게 사용할 수 없거나, 약화된 기능을 표시하지 않는 정보 메시지에 대해 WARNING을 사용하지 마십시오.

    SEVERE

    수행: 일부 기능의 전체가 손실되거나 상당부분이 손실되도록 하는 이벤트를 표시하려면 SEVERE를 사용하십시오. SEVERE 메시지의 예제는 plugin_customization.ini를 읽을 수 없을 때 플랫폼 플러그인이 기록하는 메시지입니다.
    Error loading plugin customization file

    수행 금지: 모든 기능 또는 대부분의 기능이 계속 사용 가능하거나 문제점이 일시적인 경우 SEVERE를 사용하지 마십시오.

  7. 추적 수행 방법은 무엇입니까? 개발자 전용 추적은 어떻습니까?

    기본적으로 추적은 사용하지 않습니다. 추적은 개발자, 품질 엔지니어 및 지원 부서 요원이 사용하기 위한 것입니다.

    세 가지의 추적 레벨(FINE, FINER 및 FINEST)이 있습니다.

    FINE: 문제점을 이해하거나 디버그하려고 할 때 시스템 플로우 또는 상태를 설명하는 중요한 이벤트에 대해서는 이 레벨을 사용하십시오. 이는 보통 오브젝트 작성 레벨, 오류를 생성하지 않는 예외에 대한 catch 절 등에 있습니다.

    FINER: FINER 레벨의 메시지를 생성하는 로거(logger) 메소드 세트가 있습니다. 해당 메소드는 entering(...), exitin(..), finer(..)throwing(..)입니다.
    • 메소드 entry 및 exit에 Entering 및 exiting을 사용해야 합니다.
    • Finer는 Fine에 대해 원하는 것보다 더 다양한 추적에 사용할 수 있지만 메소드 entry/exit가 아니거나 예외 발생 이전에 사용할 수 없습니다.
    • 예외를 발생하거나 다시 발생하려고 할 때 throwing을 사용해야 합니다.

    FINEST: Finest는 보통 개발자 또는 디버그 추적처럼 생각합니다. 이는 개발하는 동안 Fine 레벨의 세부사항으로 시스템 동작을 학습하려고 할 때, 그리고 코드가 릴리스될 때 어려운 문제점을 진단하려고 할 때 사용됩니다.

    추적은 개발 중 및 개발 후에 가치있는 도구입니다. 추적은 동적 사용을 지원해야 하며 java.util.logging.Logger API를 사용하여 완료되어야 합니다. 경험에 의하면, 개발 중에 가치가 있으면 나중에도 가치가 있습니다. println 또는 printStackTrace는 동적 사용 또는 레벨 관리를 지원하지 않고 대부분의 경우 문제점 판별용으로 시스템 추적 파일 사용을 시도하여 혼란을 초래하므로 절대로 사용하지 마십시오.

  8. 예외 로깅에 대해 무엇을 수행해야 합니까?
    모든 예외는 로깅 문장으로 기록해야 합니다. 보통 예외가 사소하지 않거나 다시 발생하지 않으면 WARNING 또는 SEVERE 레벨에 있습니다. 추가 가이드라인은 다음과 같습니다.
    • 항상 예외를 포함하여 로그 항목에 대해 특정 메시지를 제공하십시오. 예외의 영향을 설명해야 합니다.
    • 메시지가 아니라 예외를 로깅하십시오. 사용자 스스로 설정하지 않으면 메시지가 이해 가능하거나 존재하는지 조차 보장하지 못하게 됩니다.
    • 예외에 대해 printStackTrace를 호출하지 마십시오. 로거(logger)가 자동으로 예외에 응답하도록 허용하는 방식으로 이를 수행합니다. .
    • 예외를 발견한 후 새 예외가 발생하는 경우(종종 잘 작성된 API에서) 발생한 예외의 원인으로 발견된 예외를 사용해야 합니다. 일반적으로, 이와 같은 경우 발견된 예외는 로깅하지 말아야 합니다(이 때 스택까지의 모든 것이 동일한 가이드라인을 따른다고 가정합니다).
    • 이 정보가 사용자에게 유익하면 다른 예외를 발생시킬 경우에도 예외를 로그하는 것이 좋을 때도 있습니다.
  9. 로깅 예제는 무엇입니까?
    다음의 두 코드 샘플은 공통되는 로깅 패턴입니다.
      _logger.logp(Level.INFO, CLAZZ_NAME, METHOD,
    "Messages.PROCESS_RECS");
    예외를 로깅해야 하는 경우:
    _logger.logp(Level.SEVERE,CLAZZ_NAME,METHOD,Messages,RCP_XML_PROCESSING_ERROR
        throwable);
  10. 추적 예제는 무엇입니까?

    다음 코드 예제는 추적을 보여줍니다.

    추적 예제 1:
    if (_logger.isLoggable(Level.FINE)) 
            	            	_logger.logp(CLASS_NAME_METHOD,"Setting activities for page 
                               " + _model.getName() + ":");    	 }

    위의 예제에서는 _model.getName() 호출이 단순히 String을 리턴하는 것보다 복잡한 처리를 수행해야 한다고 가정합니다. String을 리턴하기만 하는 경우 보호가 필요하지 않습니다.

    추적 예제 2:
    	private GUID methodX(URL url, IProgressMonitor pM, boolean overrideCache) {
    
              final String METHOD="methodX";
    		if (logger.isLoggable(Level.FINER)) {
    			logger.entering(CLASSNAME, METHOD, url==
                                 null?"null":url.toExternalForm());
    		}
    		…
    	}
    이 예제에서는 URL만 입력에 대해 로깅됩니다. 다른 인수는 디버깅하는 동안 유용하지 않기 때문입니다. 종종 애플리케이션이 로드되지 않을 때 부분적으로 계산되는 부분적으로 손상된 URL에 문제점이 있으므로, 로드 호출로 전달되는 URL을 정확히 확인하는 것이 아주 중요합니다. 또한 이는 개인용 메소드입니다. 이 개인용 메소드를 호출하여 해당 작업을 수행하는 많은 공용 메소드가 있으므로, 공용 호출에 의해 여러 번 URL이 로깅되도록 하는 대신 이 메소드로 로그인을 집중시킵니다.
    		logger.exiting(CLASSNAME, METHOD, res);

    "exiting" 호출은 이 메소드에서 리턴하는 결과를 로깅하므로 잘못된 사항이 있으면 이를 해결하기 위한 디버깅용으로 매우 유용합니다.

    추적 예제 3:
    public void showApplication(URL url, String pageId, IProgressMonitor 
              progressMonitor)
    		 throws IllegalArgumentException, CompositeApplicationException {
    
        final String METHOD="showApplication";
    		if (logger.isLoggable(Level.FINER)) {
    			logger.entering(CLASSNAME, 
    				
        METHOD, 
    				new Object[] {url, pageId, progressMonitor});
    		}
    } catch (RuntimeException e) {
    			logger.logp(Level.SEVERE,CLASS NAME, METHOD
    Messages.PORTAL APP JOB UPDATE ERROR, e);
    			throw new CompositeApplicationException(e);
    		}
  11. 내 로거 레벨을 캐시해야 합니까?

    실행 중 한 번 사용자의 로거 레벨을 확인한 후 사용자 호출을 보호하려고 할 때마다 레벨을 묻는 대신 이 캐시된 레벨을 참조하는 것이 나을 수 있습니다. 그러나 이는 권장사항은 아닙니다. OSGi 명령 프롬프트와 같은 로거 레벨 구성의 동적 업데이트 사항에 코드가 응답하지 않을 수 있기 때문입니다.



라이브러리 | 지원 | | 교육 | 이용약관 |

마지막 업데이트 날짜: 2008년 10월 21일
© Copyright IBM Corporation 2006, 2008. All Rights Reserved.
이 Information Center는 Built on Eclipse™입니다. (http://www.eclipse.org 웹 사이트 참조)