Java Category/Spring

[Spring] Logging

ReBugs 2024. 2. 19.

이 글은 인프런 김영한님의 Spring 강의를 바탕으로 개인적인 정리를 위해 작성한 글입니다.


운영 시스템에서는 System.out.println() 같은 시스템 콘솔을 사용해서 필요한 정보를 출력하지 않고, 별도의 로깅 라이브러리를 사용해서 로그를 출력한다.

 

스프링 부트 라이브러리를 사용하면 스프링 부트 로깅 라이브러리(spring-boot-starter-logging)가 함께 포함된다.

스프링 부트 로깅 라이브러리는 기본으로 다음 로깅 라이브러리를 사용한다.

 

로그 라이브러리는 Logback, Log4J, Log4J2 등등 수 많은 라이브러리가 있는데, 그것을 통합해서 인터페이스로 제공하는 것이 바로 SLF4J 라이브러리다.

SLF4J는 인터페이스이고, 그 구현체로 Logback 같은 로그 라이브러리를 선택하면 된다.

실무에서는 스프링 부트가 기본으로 제공하는 Logback을 대부분 사용한다.

 

로그 선언

  • private Logger log = LoggerFactory.getLogger(getClass());
  • private static final Logger log = LoggerFactory.getLogger(Xxx.class)
  • @Slf4j : 롬복에서 제공하는 로그 어노테이션

 

로그 호출

  • log.info("hello")`

 

로그가 출력되는 포멧

  • 시간, 로그 레벨, 프로세스 ID, 쓰레드 명, 클래스명, 로그 메시지

 

올바른 로그 사용법

  • log.debug("data="+data) : 로그 출력 레벨을 info로 설정해도 해당 코드에 있는 "data="+data가 실제 실행이 되어 버린다. 결과적으로 문자 더하기 연산이 발생한다. -> 이렇게 사용하면 안된다.
  • log.debug("data={}", data) : 로그 출력 레벨을 info로 설정하면 아무일도 발생하지 않는다. 따라서 위와 같은 의미없는 연산이 발생하지 않는다.

 

실무에서는 항상 로그를 사용해야 한.

 

로그를 남기는 방법

방법 1

package hello.springmvc.basic;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController //반환 값 string 그대로 html 바디에 전송
public class LogTestController {

    private final Logger log = LoggerFactory.getLogger(getClass());

    @RequestMapping("/log-test")
    public String logTest(){
        String name = "Spring";

        //TRACE > DEBUG > INFO > WARN > ERROR
        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);

        log.debug("String concat log = " + name); //로그를 사용하지 않아도 a+b 계산 로직이 먼저 실행됨, 이런 방식으로 사용하면 X
        return "ok";
    }
}

 

방법2(@Slf4j 사용)

package hello.springmvc.basic;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController //반환 값 string 그대로 html 바디에 전송
public class LogTestController {
    @RequestMapping("/log-test")
    public String logTest(){
        String name = "Spring";

        //TRACE > DEBUG > INFO > WARN > ERROR
        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);

        //로그를 사용하지 않아도 a+b 계산 로직이 먼저 실행됨, 이런 방식으로 사용하면 X
        log.debug("String concat log = " + name);
        return "ok";
    }
}

 

@RestController
특정 클래스를 RESTful 웹 서비스의 컨트롤러로 지정한다.
이 어노테이션을 사용한 클래스는 HTTP 요청을 처리하는 핸들러 메소드를 포함하며, 각 메소드는 특정 HTTP 요청(예: GET, POST, DELETE 등)에 매핑된다.
@RestController는 @Controller 와 유사하지만, 차이점은 @RestController 로 지정된 컨트롤러의 메소드가 기본적으로 HTTP 응답 본문(Body)에 직접 데이터를 작성한다는 점이다.
이는@ResponseBody 어노테이션을 모든 핸들러 메소드에 적용한 것과 같은 효과를 가진다.


@Controller 는 반환 값이 String 이면 뷰 이름으로 인식된다.
그래서 뷰를 찾고 뷰가 랜더링 된다. @RestController 는 반환 값으로 뷰를 찾는 것이 아니라, HTTP 메시지 바디에 바로 입력한다.
@ResponseBody
웹 어플리케이션에서 컨트롤러의 핸들러 메소드가 HTTP 응답 본문(Body)에 직접 내용을 작성할 수 있도록 지정한다.
이 어노테이션은 @Controller 어노테이션이 적용된 클래스 내의 메소드에 사용될 때 유용하며, @RestController 어노테이션과는 달리, @Controller 어노테이션과 함께 사용되어야 한다.
@RestController 어노테이션은 기본적으로 모든 메소드에 @ResponseBody 를 적용한 것과 같은 효과를 제공한다.

 

로그 레벨

로그 레벨 : TRACE < DEBUG < INFO < WARN < ERROR

  • TRACE: 가장 낮은 레벨로, 시스템의 작동 상태를 매우 상세하게 추적하고자 할 때 사용된다. 애플리케이션의 흐름이나 변수의 값 변화 등을 추적하는 데 유용하다. TRACE 레벨은 주로 개발 과정에서 문제를 진단하기 위해 사용된다.
  • DEBUG: TRACE보다는 덜 상세한 정보를 제공하지만, 개발자가 코드의 실행 상태를 이해하고 문제를 진단하는 데 도움이 되는 정보를 로깅한다. DEBUG 레벨은 애플리케이션의 내부 작동 상태를 확인할 때 사용된다.
  • INFO: 애플리케이션의 일반적인 작업 진행 상황을 나타내는 데 사용된다. 예를 들어, 애플리케이션의 시작과 종료, 중요한 작업의 완료 등이 INFO 레벨로 로깅된다.
  • WARN: 잠재적인 문제를 경고하는 데 사용된다. 시스템의 작동에는 현재 영향을 주지 않지만, 향후 문제가 될 수 있는 상황이나 예상치 못한 상황을 나타낸다.
  • ERROR: 심각한 문제가 발생했음을 나타내며, 애플리케이션의 정상적인 작동을 방해하는 오류나 예외 상황을 로깅한다. ERROR 레벨의 로그는 즉각적인 주의와 대응이 필요한 상황을 나타낸다.

 

이러한 로그 레벨 구조를 통해 개발자는 로깅을 통해 애플리케이션의 다양한 상태와 이벤트를 효과적으로 모니터링하고 문제를 진단할 수 있다. 또한, 로그 레벨을 적절히 설정함으로써 필요한 정보만을 기록하여 로그 파일의 크기를 관리하고 성능 저하를 최소화할 수 있다.

 

로그 레벨 설정을 변경한 후 애플리케이션의 로깅 동작에 발생하는 변화는 다음과 같다.

  • 선택된 로그 레벨 이상의 메시지만 기록됨: 예를 들어, 로그 레벨을 INFO로 설정하면, INFO, WARN, ERROR 레벨의 로그 메시지만 기록된다. DEBUG와 TRACE 레벨의 메시지는 이보다 낮은 레벨이므로 기록되지 않는다. 이는 로그 데이터의 양을 줄이고, 로그 파일을 통해 중요한 정보에 더 쉽게 접근할 수 있게 한다.
  • 로깅 성능의 개선: 낮은 레벨의 로그 메시지(예: DEBUG와 TRACE)가 많이 생성되지 않게 되므로, 로그 기록으로 인한 성능 저하가 감소한다. 이는 특히 로그 메시지의 양이 많고 로깅이 성능에 미치는 영향이 큰 애플리케이션에서 유용하다.
  • 로그 파일 관리 용이성 증가: 필요한 정보만 로깅되므로 로그 파일의 크기가 줄어들고, 로그 관리가 용이해진다. 이는 로그 파일의 저장 공간을 절약하고, 로그 분석 과정을 간소화한다.
  • 중요 정보의 가시성 향상: 중요한 정보만 기록되기 때문에, 개발자나 시스템 관리자가 로그 파일을 통해 문제를 진단하거나 시스템의 상태를 모니터링하는 데 있어 중요한 정보에 더 쉽게 주목할 수 있다.

 

-> 개발 서버는 debug 출력 운영 서버는 info 출력

 

로그 레벨 변경 

application.properties에서 로그 레벨을 변경할 수 있다.

#전체 로그 레벨 설정(기본 info)
logging.level.root=info

#hello.springmvc 패키지와 그 하위 로그 레벨 설정
logging.level.hello.springmvc=debug

 

댓글