본문으로 건너뛰기

로그(자바기본)

자바에서 기본적으로 제공하고있는 로그 에 대해서 알아보자

기본개념

자바가 기본적으로 제공하는 로그 출력에는 Logger 클래스를 사용한다
Logger 인스턴스 취득에는 Logger.getLogger메서드를 사용한다
이때 전달하는 문자열이 로거의 이름이 된다

Logger log1 = Logger.getLogger("hoge");

로거는 이름을 기준으로 계층구조를 만들수 있다

Logger log1 = Logger.getLogger("hoge");
Logger log2 = Logger.getLogger("hoge.foo");

자식 로그는 부모 로그의 설정치를 계승한다

로그레벨

  • Level.SEVERE - 중대한 장애
  • Level.WARNING - 경고, 계속적 실행은 가능하지만 장애
  • Level.INFO - 정보
  • Level.CONFIG - 설정치
  • Level.FINE - 트레이스 정보
  • Level.FINER - 보다 자세한 정보
  • Level.FINEST - 꾀나 상세한 정보

Handler클래스

Logger 클래스에서 실제로 로그를 출력하는것은 Handler클래스이다. Handler클래스는 추상클래스 이므로, 출력하는 곳을 바꾸고 싶을 경우에는, 그 출력하는곳 용의 Handler클래스를 정의해서 Logger인스턴스에 설정하면 된다.
출력 하는곳의 종류에는 표준에러 출력 / 파일 / 소켓 이 있다

Filter 클래스

로그를 필터링해서도 출력할 수 있다.

Apache log4j에 대해서

자바에서 로깅 API가 추가된것이 1.4버전인데
1.4이전까지는 외부 라이브러리를 사용해서 로깅을 했어야만 했다
그때 많이 사용된것이 log4j이고 그것이 아직까지도 쭈욱 이어져 온것이다
log4j는 로그내용을 파일뿐만이 아니라 데이터베이스에 담을수도 있고,
윈도우의 이벤트 내용에 기록할수도 있다.
이 부분이 log4j 의 취약성이 되기도 했지.. ㅋ

소스로 달려 !!

기본. 로그 출력

public class ExerciseLog {

static Logger logger = Logger.getLogger("Logging");

public static void main(String[] args) {

logger.log(Level.INFO, "로그 출력입니다");

logger.log(
Level.INFO, "{0}를 {1}합니다",
new String[] {"로그", "출력"}
);

logger.log(
Level.INFO, "예외를 로그에 출력합니다", new Exception()
);

/**
* logp메서드를 통해서 로그를 출력할 경우에는
* 로그 출력을 하고있는 클래스명
* 로그 출력을 하고있는 메서드명
* 을 지정해준다
*/
logger.logp(
Level.INFO, "ExerciseLog", "main", "logp 로그를 출력합시다"
);

logger.info("로그 출력을 하였습니다");
}
}
2월 06, 2022 4:25:35 오후 org.example.ExerciseLog main
INFO: 로그 출력입니다
2월 06, 2022 4:25:35 오후 org.example.ExerciseLog main
INFO: 로그를 출력합니다
2월 06, 2022 4:25:35 오후 org.example.ExerciseLog main
INFO: 예외를 로그에 출력합니다
java.lang.Exception
at org.example.ExerciseLog.main(ExerciseLog.java:21)

2월 06, 2022 4:25:35 오후 ExerciseLog main
INFO: 로그를 출력합시다
2월 06, 2022 4:25:35 오후 org.example.ExerciseLog main
INFO: 로그 출력을 하였습니다

Logger.getLogger메서드를 사용해서 인스턴스화 한다. 그때 파라미터로 로그명을 넘기는데,
보통 그 클래스의 페키지명이나 클래명을 적는다
Logger클래스는 스레드 세이프 하기때문에 대부분의 경우 여러 메서드에서 사용 가능하도록 static 으로 선언한다

Logger.log 메서드는 Logging.java 에서 제시한 3가지의 패턴으로 많이 사용된다

  • 로그 레벨을 지정한 후에 메세지를 기술
  • 메세지 내부에서 가변적인 부분을 {}로 작성하고 그다음에 그곳에 바인딩할 오브젝트를 배열로 기술
  • 예외를 기술 이렇게 3패턴이다

Logger.logp메서드도 log메서드와 거의 같다. 다만 로그를 출력하는 클래스와 메서드명을 지정하는 것이 가능하다.
log메서드는 매번 클래스명과 메서드명을 찾는 작업을 하는데, logp같은 명우는 명시적으로 클래스와 메서드명을 지정해주기 때문에 속도측면에서 조금더 빠르다

Logger.info 메서드같이 로그 레벨을 소문자로한것이 그대로 이름이 되는것들이 있다. 그런것들은 로그 레벨을 그대로 표현해준다

로그 출력의 설정을 변경

public class ExerciseLog {

static Logger logger = Logger.getLogger("Logging");

public static void main(String[] args) {

logger.log(Level.INFO, "로그를 출력한다 (INFO)");
logger.log(Level.FINE, "로그를 출력한다 (FINE)");

}
}
2월 21, 2022 2:33:51 오전 org.example.ExerciseLog main
INFO: 로그를 출력한다 (INFO)

FINE 레벨이 나오지 않는다. 나오게 하려면 log.properties를 손봐야한다.

윈도우 기준이라면 이렇게 하면 된다고 책에는 나와있... -_-;;; 이런게 있다는 정도만 알고있자

java -Djava.util.logging.config.file=c:\work\logging.properties Logging

로그를 파일로 출력

public class ExerciseLog {

static Logger logger;

static void initializeLog() throws Exception {

// 인스턴스를 취득
logger = Logger.getLogger("LogFile");

// 파일 핸들러를 로그에 추가
FileHandler fileHandler = new FileHandler("%h/sample_%g.log", 10000, 2, true);

// 모든 레벨의 로그를 출력하도록 설정
fileHandler.setLevel(Level.ALL);

// 서식을 심플 포맷으로 지정함
fileHandler.setFormatter(new SimpleFormatter());

// 로그 파일의 문자코드를 지정
fileHandler.setEncoding("utf-8");

// 로그에 핸들러를 추가
logger.addHandler(fileHandler);

// 모든 로그를 출력하도록 설정
logger.setLevel(Level.ALL);
}

public static void main(String[] args) throws Exception {

initializeLog();

logger.log(Level.INFO, "로그 출력 INFO");
logger.log(Level.FINE, "로그 출력 FINE");
logger.log(Level.FINEST, "로그 출력 FINEST");

}

}

이렇게 파일로 만들어진다.

  • %h : 홈 디렉토리
  • %g : 로테이션을 식별하는 번호

10000바이트를 넘어가면 sample_0.log 가 sample_1.log 로 리네임 되고, sample_0.log 로 새롭게 쓰기 시작한다.
로그파일을 놔두는걸 2로 지정했기 때문에. 이걸넘어가면 그 이상은 삭제가 되면서 로테이션 된다.

cat sample_0.log
2월 21, 2022 2:42:14 오전 org.example.ExerciseLog main
INFO: 로그 출력 INFO
2월 21, 2022 2:42:14 오전 org.example.ExerciseLog main
FINE: 로그 출력 FINE
2월 21, 2022 2:42:14 오전 org.example.ExerciseLog main
FINEST: 로그 출력 FINEST