정보를 제공하는 일련의 기록인 로그(log)를 생성하도록 시스템을 작성하는 활동이다. 평소 우리는 콘솔 창에 일련의 정보를 나타내고 싶다면 System.out.println(”...”); 을 사용하였겠지만 실무에서는 저런 허접한 메서드를 사용하지 않는다. sout을 사용하지 않는 이유와 로그를 생성할 수 있는 다른 방법을 알아보자.
콘솔창에 띄워서 정보를 제공하는데에 sout을 사용해도 상관없다고 생각할 수 있지만 실무에서 로그를 띄울 때 sout을 사용하지 않는데는 이유가 있다. → 물론 개발서버에서는 개발자가 이것저것 확인해본다는 가정하에 사용할 수 있지만 운영서버에서는 절대 사용하지 말자
우리가 운영서버에 sout으로 로그를 찍었다 → 사용자가 수십 수백명인 서비스에서는 큰 문제가 일어나지 않을 수 도 있지만 만약 사용자가 수십 수백만명이 있는 서비스에서 저런 로그를 찍으면 서버에 무리가 가고 성능 저하 이슈가 생길 수 있다.
로그 메서드를 사용하고 싶다면 Logger라는 클래스를 참조하는 변수를 만들어 사용해야한다.
private final Logger log = LoggerFactory.getLogger(getClass());
String name = "log";
log.trace("log trace {}" + name);
“아니 우리가 어느 시대인데 저렇게 긴 코드를 맨날 쓰고 로그를 사용해야 하냐”와 같은 궁금증이 생길 수 있는데 당연히 해결책이 있다.
Log4j와 Slf4j는 Lombok이라는 라이브러리에서 지원하는 어노테이션이므로 build.gradle에서 lombok 라이브러리 의존성을 추가해주어야 한다.
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
기본적으로 위와 같은 코드를 간단하게 대체할 수 있는 어노테이션이 Log4j이다.
@Log4j
public ...{
String name = "log";
log.trace("log trace {}" + name);
}
Slf4j = java.util.logging, logback + log4j 라고 보면 편하다. 결국 Slf4j는 Log4j보다 더 성능이 좋고 최적화 된 어노테이션이라는 뜻이다.
@Slf4j
public ...{
String name = "log";
log.trace("log trace {}" + name);
}
지금까지 로그와 Logfj, Slf4j에 대해서 알아보았다. 지금부터는 로그 출력 방법에 대해서 알아보자.
로그에는 5가지 레벨(Level)이 있다. 위험도를 나타내는 수준에 따라 로깅 레벨이 다르다.
Info 레벨부터는 콘솔에 로그가 찍힌다.
기본적인 로그 출력 방법은 sout과 비슷하다
String name = "Spring";
String warn = "아 이건 좀 위험하다";
String error = "아 큰일이다 빨리 고쳐야해";
System.out.println("name = " + name);
log.trace("trace log = {}", name);
log.debug("debug log = {}", name);
log.info("info log = {}", name);
log.warn("warn log = {}", warn);
log.error("error log = {}", error);
위에서 Log4j → Slf4j가 되면서 어느정도의 성능의 최적화가 되긴했지만 아직 문제점이 있다. 우리가 sout을 사용하지 않는 이유가 사용자가 많아지고 그에 따라 로그의 수가 늘어나면 결국 성능 저하 이슈가 발생할 수 있기 때문이라고 말했는데, 위의 출력을 보면 결국 INFO, WARN, ERROR 3가지 레벨의 로그는 무조건 다 출력하고있다
그래서 스프링에서는 이런 문제의 해결방안을 제시하였는데 바로 properties 또는 yml 파일에서의 설정이다.
application.yml
logging.level.tobyAndSpring.studySpring.controller.LogTestController : WARN
경로 + 어느 레벨부터 콘솔에 로그를 출력할 것인지에 대한 설정을 해준 모습이다. 위와 같은 설정을 해주면 아래와 같이 설정해준 로그부터 그 윗단계 로그들을 출력해준다.
String name = "log";
// 두 개의 의미는 같을까 ?
log.info("info log = {}", name);
log.info("info log = " + name);
결론부터 말하자면 2개의 의미는 같다. 하지만 두 번째 출력 방식은 사용하면 안된다. 그 이유는 자바 언어 자체의 특징 때문에 그런데, 단계별로 풀어서 보자.
yml에서 WARN으로 설정해준 상태
log.info("info log = " + name);
log.info("info log = name");
아니 어차피 WARN으로 설정해서 출력되지 않음에도 불구하고 이미 JRE에서는 + 연산을 마치고 값을 가지고 있는 상태이다. 하지만 { } 를 사용하면 불필요한 연산이 일어나지 않으므로 성능면에서 더욱 강력한 최적화가 이루어진다.