tools & libs/로깅

[logging] logging과 slf4j

  • -

일반적으로 프로그램 초반에는 디버깅을 위해 System.out.println()을 코드에 적으며  오류를 추적한다. 하지만 조금만 프로그램의 덩치가 커지면 이것이 얼마나 힘든 일인지 알게 된다.

이번 포스팅에서는 더 이상 우리 코드에서 로깅을 위해 System.out.println()을 사용하지 않기를 염원하며 logging framework의 사용법에 대해 알아보자.

 

logging의 주요 용도

일반적으로 logging은 두 가지 용도로 사용된다.

디버깅

가장 기본적인 용도는 디버깅을 위한 메시지 출력이다. 메서드가 어떤 파라미터로 호출되는지, 중간에 값은 어떻게 변경되고 있는지 등을 확인하기 위해 우리는 부단히도 Systme.out.println()으로 로그를 찍어댄다.

public int add(String a, String b) {
	System.out.println("파라미터 잘 들어오나? ㅜㅜ: "+a+", "+b);
	int result = 0;
	try {
		result = Integer.parseInt(a) + Integer.parseInt(b);
	}catch(NumberFormatException e) {
		System.out.println("예외 발생: "+e.getMessage());
	}
	System.out.println("여기까지 오면 결과 생성됨: "+result);
	return result;
}

위는 현재 작성하고 있는 메서드에 대해서 디버깅 메시지를 만든것이다. 여기에 지적질을 해보자.

가장 심각한 것은 출력되는 로그가 어느 정도 심각한 것인지 즉 예외 처리에 대한 것인지, 단순히 파라미터 확인을 위한 것인지 구별되지가 않는다. 또한 언제 동작한 코드인지 시간 메시지도 없고 어떤 클래스에서 어떤 메서드가 동작했는지 등 상세한 내용을 파악하기 어렵다. 물론 문자열로 만들 수는 있겠지만 손이 아주 많이 갈 것이다.

아무튼 우여곡절 끝에 로깅을 잘 했고 애플리케이션이 완성됐다고 하자. 애플리케이션을 고객사에 납품할 때가 되면 어떻게 해야 할까? 설마 고객의 콘솔에 위와 같은 메시지가 출력되기를 바라지는 않을 것이다.

그렇다! 납품 할 때는 다시 로그들을 지워야 한다.  무작정 System.out.println을 지우다가는 큰일이다. 오류 발생과 같은 내용은 시스템 유지 보수에 아주 중요한 메시지이기 때문에 잘 살펴서 불필요한 것들만 지워야 한다. 열심히 디버깅 코드들을 지우고 납품한 어느 날 고객으로부터 프로그램 오류에 대한 처리 요청이 들어온다. 소스를 살펴보니 디버깅을 위한 내용들이 하나도 없다. 다시 열심히 System.out.println()을 찍어대고 있는 나를 발견한다. 즉 상황에 따라서 로그을 보이거나 숨길 수 있어야 하겠다.

 

장기간 동작하는 시스템 상태에 대한 기록

다음은 웹 페이지에서 사용자의 요청을 받은 시간, 사용자의 ip, 사용자의 요청이름을 로깅한다.

private void process(HttpServletRequest request, HttpServletResponse response) throws Exception {
  String act = request.getParameter("act");
  System.out.println("요청 접수"+new Date()+",경로: "+request.getRemoteAddr()+" , 요청명: "+act);
  if ("mvjoin".equals(act)) {
    // do something
  }
}

 

위 로그를 콘솔에 찍고 모니터링할 수 있는 건 수업시간에 하는 예제 정도이다. 실제 서버는 1년 365일 돌아가야 하는데 콘솔의 메모리가 저런 로그를 언제까지 보관해 둘 수는 없다. 따라서 로그는 파일 등에 저장되어야 하고 파일의 크기가 무한대로 커질 수 없기 때문에 롤링등에 대한 처리가 필요하다.

대충 생각해도 이를 위한 I/O 처리를 위한 프로그래밍이 상당히 필요해 보인다. 

이런 필요성으로 등장하는 것이 로깅 프레임워크(logging framework)이다.

 

Slf4j(Simple Logging Facade for Java)

 

Slf4j

이런 logging framework에서 빼놓을 수 없는 것이 Slf4j(Simple Logging Facade for Java)이다. 이름 그대로 보면 java에서 logging을 위한 facade(정면, 건물의 전면)이다. facade 패턴은 라이브러리(프레임워크)에 대한 복잡한 구조에 대해 단순화된 인터페이스를 제공하는 패턴이다. JDBC의 인터페이스와 각 벤더사가 구현해 놓은 드라이버도 이 패턴이다.

아무튼 Slf4j는 로깅에 필요한 메서드 즉 기능들을 선언해 놓은 interface이고 이것의 구현체로 log4j, logback 등이 있다. 

 

code의 입장에서는 Slf4j만 알면 된다. log4j든 logback이든 잘 되겟지!

 

그럼 Slf4j는 위에서 언급했던 System.out.println() 기반 로그 문제를 어떻게 개선하고 있을까?

 

로그 레벨

Slf4J는 심각도에 따라  trace > debug > info > warn > error 다섯 단계의 레벨로 로그를 관리한다. 따라서 trace 수준의 로그에 숨겨져 있는 error를 놓칠 가능성이 훨씬 줄어들게 된다.

사용할 때는 설정을 통해서 출력할 로그의 레벨을 지정할 수 있다. 예를 들어 trace로 설정하면 5단계의 모든 로그를 확인할 수 있지만 info로 설정하면 trace, debug는 무시하고 info, warn, error만 출력 한다. 이제 로그를 썼다 지웠다 할 필요가 없어졌다.

일반적으로 개발 과정에서는 trace, debug를 사용하고 운영 과정에서는  info 이상의 레벨이 사용된다.

 

로그 레이아웃

역시 설정을 통해 어떤 형식으로 로그를 남길 것인지 로그의 패턴을 작성할 수 있다. 다음은 간단한 패턴의 예이다.

%d{HH:mm:ss} [%-5level] %logger{1.} - %msg%n

만약 위의 패턴이 적용된 상태에서 로그를 남기면 풍성한 정보를 가지는 로그를 볼 수 있다.

// 호출
log.info("message");

// 로그 결과
12:30:45 [INFO ] c.m.MyService - message

 

다양한 Appender 제공

Appender란 로깅 이벤트를 처리하는 컴포넌트이다. logging framework 들은 Appender를 이용해서 다양한 방식으로 로그를 출력할 수 있게 도와준다. 다음은 logback에서 제공하는 Appender의 내용이다. 

출처: https://logback.qos.ch/manual/images/chapters/appenders/appenderClassDiagram.jpg

 

  • ConsoleAppender:  콘솔에 로그를 출력한다.
  • FileAppender: 파일에 로그를 출력한다.
  • RollingFileAppender: 파일 순환을 통해서 장기간 파일에 로그를 출력한다.

이 외에도 SMTP 지원, JDBC 지원 등 다양한 Appender를 구현체들이 제공한다. 다 만들어 놓았으니까 쓰기만 하면 된다.

 

심심한가요?

심심하다면 아래 글도 한번 읽어보자. http://logback.qos.ch/reasonsToSwitch.html

 

Reasons to prefer logback

Reasons to prefer logback over log4j Logback brings a very large number of improvements over log4j, big and small. They are too many to enumerate exhaustively. Nevertheless, here is a non-exhaustive list of reasons for switching to logback from log4j. Keep

logback.qos.ch

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.