3. Logger 클래스
1.Logger
Logger 클래스는 로그 기록을 남기는 역할을 수행하는 클래스
Logger 클래스의 객체(인스턴스)는 일반적으로 getLogger()와 같은 팩토리 메서드(Factory Method) 패턴을 통해 생성할 수 있음
개발자는 로그 기록을 출력하기 위한 곳에서 해당 Logger 객체를 생성 후 간단하게 로그를 작성할 수 있음
public class Main {
// Logger 객체 생성, Logger 객체를 필드로 초기화
private static final Logger logger = Logger.getLogger(Step01Logging.class.getName());
public static void main(String[] args) {
logger.log(Level.INFO, "INFO 레벨 출력용 테스트 메시지"); // INFO 레벨 출력
logger.log(Level.WARNING, "WARNING 레벨 출력용 테스트 메시지");
logger.log(Level.FINE, "FINE 레벨 출력용 테스트 메시지");
logger.log(Level.FINER, "FINER 레벨 출력용 테스트 메시지");
}
}출력 결과
"INFO 레벨 출력용 테스트 메시지"
"WARNING 레벨 출력용 테스트 메시지"
"FINE 레벨 출력용 테스트 메시지"
"FINER 레벨 출력용 테스트 메시지"2. 로그를 남기는 방법
로그를 남기기 위해서는 남길 로그 메시지와 해당 메시지의 적절한 로그 레벨을 설정하면 됨
경고 레벨(WARNING)의 로그 출력
logger.log(Level.WARNING, "23:10:02, System 수준 에러 발생");시스템 내 일반적인 정보 확인 용도 레벨(INFO)의 로그 출력
logger.log(Level.INFO, "22:09:05, oo 사용자가 로그인하였음");log()의 내부 코드
public void log(Level level, String msg) {
if (!isLoggable(level)) {
return;
}
LogRecord lr = new LogRecord(level, msg);
doLog(lr);
}2-1. 보다 직관적인 로그 메서드 활용하기
Logger 클래스는 개발자가 로그 메시지를 보다 직관적으로 작성할 수 있도록 하기 위해 몇 가지 유틸 메서드를 제공함
ex) fine(), finer(), severe(), warning()
→ Logger 문서의 Method Summary에서 확인해보기
위의 방법보다 더 직관적이고 간소화된 방식으로 로그 레벨을 메서드 이름으로 추상화한 스타일
logger.warning("23:10:02, System 수준 에러 발생");
logger.info("22:09:05, oo 사용자가 로그인하였음");내부 호출 코드
public void warning(String msg) {
log(Level.WARNING, msg);
}→ 결과적으로 log()의 호출을 추상화시킨 메서드라고 볼 수 있음
3. 로그 레벨(수준)
각 메서드들(warning(), info())은 자신만의 로그 레벨(Log level)을 가지고 있음
→ 보다 자세한 내용은 4. Level 클래스 참고
로그 레벨
로그 레벨이란 프로그램 운영 중에 발생되는 정보들을 위험도, 중요도 등에 따라 위계를 구분하여 관리하기 위해 사용되는 개념,
→ Level 객체를 통해 관리됨
logger.log(Level.WARNING, "23:10:02, System 수준 에러 발생");→ 인수로 Level 객체를 전달하고 있음
로깅 메서드 log()의 시그니처
/**
* Log a message
* If the logger is currently enabled for the given message
* level then the given message is forwarded to all the
* registered output Handler objects.
로거 객체가 인수로 전달받은 레벨로 활성화되어 있을 경우,
주어진 메시지(msg)를 등록된 모든 핸들러 객체에게 전달
* @param level One of the message level identifiers, e.g., SEVERE
* @param msg The string message (or a key in the message catalog)
*/
public void log(Level level, String msg) {
if (!isLoggable(level)) { // 로깅 허용 레벨이 아닐 경우 폐기
return;
}
LogRecord lr = new LogRecord(level, msg);
doLog(lr);
}
/**
Check if a message of the given level would actually be logged by this logger.
This check is based on the Loggers effective level, which may be inherited from its parent.
Params: level – a message logging level
Returns: true if the given message level is currently being logged.
*/
public boolean isLoggable(Level level) {
int levelValue = config.levelValue; // new ConfigurationData() 참고
// 전달된 레벨의 값이 기본값(INFO)보다 낮을 경우 or 로깅이 아예 비활성화일 경우 로깅 불가
if (level.intValue() < levelValue || levelValue == offValue) {
return false;
}
return true;
}4. Logger 객체의 생성 과정
Logger 객체는 LogManager를 통해 생성됨
1-1. LogManager
Logger.java 내부 구현 코드
public static Logger getLogger(String name) {
return Logger.getLogger(name, Reflection.getCallerClass());
}
private static Logger getLogger(String name, Class<?> callerClass) {
return demandLogger(name, null, callerClass);
}
private static Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
LogManager manager = LogManager.getLogManager();
if (!SystemLoggerHelper.disableCallerCheck) {
if (isSystem(caller.getModule())) {
return manager.demandSystemLogger(name, resourceBundleName, caller);
}
}
return manager.demandLogger(name, resourceBundleName, caller);LogManager.java 내부 구현 코드
Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
final Module module = caller == null ? null : caller.getModule();
return demandLogger(name, resourceBundleName, module);
}
Logger demandLogger(String name, String resourceBundleName, Module module) {
Logger result = getLogger(name);
if (result == null) {
// only allocate the new logger once
Logger newLogger = new Logger(name, resourceBundleName,
module, this, false);
do {
if (addLogger(newLogger)) {
return newLogger;
}
} while (result == null);
}
return result;
}