시스템
을 작동할 때 시스템
의 작동 상태
의 기록
과 보존
, 이용자의 습성 조사
및 시스템 동작
의 분석
등을 하기 위해 작동중의 각종 정보를 기록
해둘 필요가 있다. 이 기록을 만드는 것을 로깅
이라 한다. 즉 로그 시스템의 사용에 관계된 일련의 사건을시간의 경과에 따라 기록하는 것이다.
운영 시스템에서는
System.out.println()
같은 시스템 콘솔을 사용해서 필요한 정보를 출력하지 않고, 별도의 로깅 라이브러리를 사용해서 로그를 출력한다.
로깅 라이브러리는 스프링 부트 라이브러리를 사용하면 자동으로 포함된다.
로그 라이브러리는Logback
,Log4J
,Log4J2
등 많은 라이브러리가 있는데, 이것들을 통합해서 인터페이스로 제공하는 것이SLF4J
라이브러리다.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LogTestController {
private final Logger log = LoggerFactory.getLogger(LogTestController.class);
}
또는
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class LogTestController{...}
로그를 선언하는 방법은 첫번째 코드처럼 private final Logger log = LoggerFactory.getLogger(LogTestController.class);
를 작성해주는 방법도 있지만 간단하게 @Slf4j
애노테이션을 추가하는 방법도 존재한다.
로그 호출은 다음과 같은 형식으로 할 수 있다.
log.info("hello")
그렇다면 System.out.println("hello)
와 log.info("hello")
의 차이는 무엇일까?
아래 코드를 실행해서 차이점을 알아보자
package hello.springmvc.basic;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class LogTestController {
@RequestMapping("/log-test")
public String logTest() {
String name = "spring";
System.out.println("name = " + name);
log.info("info log={}", name);
return "ok";
}
}
출력
출력 결과의 차이가 분명하게 보인다. 로그는 시스템 출력과 다르게 쓰레드 정보, 클래스 이름, 시각 등 부가 정보를 볼 수 있다는 것을 알 수 있다. 또한 출력 결과에서는 알 수 없지만 성능도 System.out보다 좋다.
package hello.springmvc.basic;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class LogTestController {
@RequestMapping("/log-test")
public String logTest() {
String name = "spring";
log.trace("trace log={}", name);
log.debug("debug log={}", name);
log.info("info log={}", name);
log.warn("warn log={}", name);
log.error("error log={}", name);
return "ok";
}
}
로그는 위 코드에서 보이는 것처럼 trace
, debug
, info
, warn
, error
출력이 존재한다. 한 번 출력 결과를 확인해보자.
출력
그런데 분명 나는 trace, debug, info, warn, error을 출력하였는데 출력 결과를 보니 trace
, debug
출력이 보이지 않는다. 왜일까?
이를 해결하기 위해서는 로그 레벨을 설정해야한다.
로그 레벨 설정을 변경해서 원하는 출력 결과를 만들어보자.
TRACE
> DEBUG
> INFO
> WARN
> ERROR
DEBUG
레벨에서 출력INFO
레벨에서 출력로그 레벨을 설정하기 위해서는 application.properties
를 변경해야한다.
application.properties
에 다음과 같은 설정을 추가하자
#전체 로그 레벨 설정(기본 info)
logging.level.root = info
#hello.springmvc 패키지와 그 하위 로그 레벨 설정
logging.level.hello.springmvc=trace
가장 상위 레벨인 trace
로 패키지와 하위 로그 레벨을 설정하였다. 이제 다시 출력 결과를 확인해보자
출력
trace
, debug
, info
, warn
, error
레벨이 모두 출력되는 것을 확인할 수 있다.
log.debug("data=" + data)
log.debug("data=", data)
위 두 줄의 코드는 모두 같은 출력 결과를 가질 것이. 그러나 log.debug("data=" + data)
는 잘못된 로그의 사용방법이다. 이유를 알아보자!
log.debug("data=" + data)
로그 출력 레벨이 info
라면 위의 debug
로그는 출력되지 않을 것이다. 하지만 "data=" + data
는 실제 실행이 된다. 이는 의미없는 연산을 발생시키고 불필요하게 리소스
를 소모한다.
log.debug("data=", data)
하지만 위의 코드는 로그 출력 레벨을 info
로 설정해도 아무런 연산도 발생하지 않는다.
의미없는 연산을 하지 않는 log.debug("data=", data)
형식이 올바른 로그 사용법이다.
쓰레드 정보
,클래스 이름
같은 부가 정보를 함께 볼 수 있고, 출력 모양을 조정할 수 있다.- 로그 레벨에 따라 개발 서버에서는 모든 로그를 출력하고, 운영서버에서는 출력하지 않는 등 로그를 상황에 맞게 조절할 수 있다.
- 시스템 아웃 콘솔에만 출력하는 것이 아니라, 파일이나 네트워크 등, 로그를 별도의 위치에 남길 수 있다. 특히 파일로 남길 때는 일별, 특정 용량에 따라 로그를 분할하는 것도 가능하다.
- 성능도 일반
System.out
보다 좋다.
출처
김영한님의 Spring MVC 강의
SLF4J - http://www.slf4j.org
Logback - http://logback.qos.ch