Java 표준 로깅 프레임워크 java.util.logging 활용하기

자바 기본 로깅 시스템 이해하기

자바는 1.4.2 버전부터 java.util.logging 패키지를 통해 내장형 로깅 기능을 제공합니다. 이 API의 핵심은 Logger 클래스이며, 애플리케이션의 문제 진단 및 실행 흐름 추적에 매우 유용합니다. 서버 장애나 예외 발생 시, 로그를 통해 원인을 정확히 파악할 수 있습니다.

로그 레벨은 총 8단계로 구성되며, 우선순위는 다음과 같습니다: SEVERE > WARNING > INFO > CONFIG > FINE > FINER > FINEST > ALL. 숫자 값으로는 더 높은 우선순위일수록 작은 값을 가지며, 현재 설정된 레벨보다 낮은 중요도의 메시지는 기록되지 않습니다. 예를 들어, 레벨이 WARNING으로 설정되면 INFO 메시지는 출력되지 않습니다.

주요 구성 요소

  • Logger: 로그 기록 요청을 처리하는 주체입니다.
  • Level: 로그의 중요도를 정의합니다.
  • Handler: 로그 출력 방식을 결정합니다 (콘솔, 파일 등).
  • Formatter: 로그 출력 형식을 지정합니다.
  • Filter: 조건에 따라 특정 로그만 기록할 수 있도록 필터링합니다.
  • LogRecord: 로그 항목 하나를 표현하는 데이터 객체입니다.

동작 구조 분석

로깅 시스템은 LogManager 싱글턴 인스턴스를 기반으로 초기화됩니다. 최상위 노드인 root logger가 생성되며, 나머지 Logger 객체는 필요 시 지연 생성(lazy loading)됩니다. 이는 자원 절약과 성능 향상을 위한 전략입니다.

다음 코드를 살펴보겠습니다:

public class LoggingExample {
    public static void main(String[] args) {
        Logger logger = Logger.getLogger("com.example.app");
        logger.info("애플리케이션이 시작되었습니다.");
    }
}

내부 동작 흐름

  1. Logger.getLogger() 호출 시, LogManager에서 기존 인스턴스 검색 또는 새로 생성합니다.
  2. 해당 Logger의 레벨(levelValue)과 요청된 메시지 레벨을 비교합니다. 통과하면 다음 단계로 진행됩니다.
  3. LogRecord 객체를 생성하여 메시지, 타임스탬프, 클래스/메서드 정보 등을 담습니다.
  4. 등록된 Filter가 있다면 isLoggable() 메서드로 추가 검증을 수행합니다.
  5. 현재 Logger와 부모 계층 구조 상 모든 Handler에게 publish 요청을 전달합니다.

Filter를 통한 고급 제어

기본 레벨 외에도 사용자 정의 필터를 적용하여 보다 세밀한 제어가 가능합니다. 아래는 특정 패키지의 로그만 허용하는 필터 예제입니다:

public class PackageFilter implements Filter {
    private final String allowedPackage;

    public PackageFilter(String packageName) {
        this.allowedPackage = packageName;
    }

    @Override
    public boolean isLoggable(LogRecord record) {
        String loggerName = record.getLoggerName();
        return loggerName != null && loggerName.startsWith(allowedPackage);
    }
}

// 사용 예시
Logger appLogger = Logger.getLogger("com.example.service");
appLogger.setFilter(new PackageFilter("com.example"));

Handler 종류와 활용

다양한 출력 대상에 맞는 Handler를 제공하며, 하나의 Logger에 여러 Handler를 연결할 수 있습니다.

대표적인 Handler 설명

  • ConsoleHandler: System.err로 출력. 개발 중 디버깅에 적합.
  • FileHandler: 로컬 파일에 저장. 용량 제한 및 회전(rotaion) 기능 지원.
  • SocketHandler: 원격 서버로 로그 스트리밍 전송.
  • MemoryHandler: 메모리 버퍼에 임시 저장 후 조건 충족 시 다른 Handler로 전달.

MemoryHandler 예제

중요 오류(SEVERE) 발생 시에만 로그를 파일로 저장하고 싶은 경우:

FileHandler fileHandler = new FileHandler("errors.log");
MemoryHandler memoryHandler = new MemoryHandler(
    fileHandler,     // 대상 핸들러
    100,             // 버퍼 크기
    Level.SEVERE,    // flush 트리거 레벨
    true             // push 액션 후 flush 여부
);

Logger logger = Logger.getLogger("critical.module");
logger.addHandler(memoryHandler);

설정 파일: logging.properties

JVM 전체 또는 애플리케이션별로 logging.properties 파일로 기본 설정을 관리할 수 있습니다. 위치는 일반적으로 $JAVA_HOME/jre/lib/logging.properties이며, 커스텀 파일은 시스템 속성으로 지정 가능합니다:

java -Djava.util.logging.config.file=mylogging.properties MyApp

예제 설정 내용:

handlers=java.util.logging.ConsoleHandler, java.util.logging.FileHandler
.level=INFO

# 콘솔 출력 설정
java.util.logging.ConsoleHandler.level=WARNING
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter

# 파일 출력 설정
java.util.logging.FileHandler.pattern=app.%u.%g.log
java.util.logging.FileHandler.limit=10485760
java.util.logging.FileHandler.count=5
java.util.logging.FileHandler.formatter=java.util.logging.XMLFormatter

# 특정 로거 레벨 조정
com.example.service.level=FINE

이 설정은 전역 레벨을 INFO로 유지하면서, 콘솔에는 WARNING 이상만 출력하고, 파일에는 XML 형식으로 상세 기록을 남기는 복합 전략을 구현합니다.

태그: java logging java.util.logging Logger Handler

7월 18일 08:14에 게시됨