yeon's blog

[Spring] 로그(Log)와 로깅 프레임워크(Logging Framework) 본문

Spring/Spring 개념

[Spring] 로그(Log)와 로깅 프레임워크(Logging Framework)

yeonii 2024. 1. 13. 20:38

System.out.print()

System.out.print()로 콘솔을 남기게 되면 문제가 있다. print() 메서드는 syncrhonized로 동기화가 되어있어, 기록을 남길 때마다 lock이 걸려 엄청난 성능 저하를 불러 일으키게 된다. 개발 단계에서 이를 사용한 후 방치해두면 I/O 요청이 발생할 때마다 쓸데없는 리소스를 잡아먹게 될 것이다.

 

로그(Log)

로그(Log)는 기록을 남기는 것으로, 로깅을 하면 앱 개발시 발생하는 문제점을 모니터링하거나 추적하는 데 용이하다. 또한 해당 데이터를 분석해 통계를 낼 수도 있다. 하지만 로그를 잘못 사용하면 문제가 생길 수도 있기 때문에, 효율적으로 로깅하는 방법을 이해해야 한다.

 

참고로 로그 관련 라이브러리도 많고, 깊게 들어가면 끝이 없기 때문에 최소한의 사용 방법만 알아보려 한다.

 

로깅 라이브러리

스프링 부트에선 기본적으로 Logback이 설정되어 있다. 다음과 같이 스프링 부트 로깅 라이브러리(spring-boot-starter-logging)가 함께 포함되어 SLF4J의 3가지 모듈이 Logback과 연결된다.

 

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

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

 

로그 선언

1) @Slf4j : 롬복 사용 가능
2) private final Logger log = LoggerFactory.getLogger(getClass());
3) private static final Logger log = LoggerFactory.getLogger(LogTestController.class);

 

로그 호출

1) log.info("hello)
2) System.out.println("hello")

 

LogTestController 전체코드

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
public class LogTestController {

//    private final Logger log = LoggerFactory.getLogger(getClass());
//    private static final Logger log = LoggerFactory.getLogger(LogTestController.class);

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

        log.trace("trace log={}", name);
        log.debug("debug log={}", name);
        log.info(" info log={}", name); // default
        log.warn(" warn log={}", name);
        log.error("error log={}", name);

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

        return "ok";
    }
}

 

매핑 정보

  • @Controller: 반환 값이 String이면 뷰 이름으로 인식 → 뷰를 찾고 뷰가 렌더링 됨
  • @RestController: 반환 값으로 뷰를 찾는 것이 아니라, HTTP 메시지 바디에 바로 입력

 

테스트

  • 로그가 출력되는 포맷 확인
    • 시간, 로그 레벨, 프로세스 ID, 쓰레드 명, 클래스 명, 로그 메시지 출력
  • 로그 레벨 설정을 변경해서 출력 결과보기
    • LEVEL: Trace > Debug > Info > Warn > Error
    • 개발 서버는 debug 출력
    • 운영 서버는 info 출력
  • @Slf4j 애노테이션 사용해보기
    • spring-boot-starter-web 의존성을 추가했다며, @Slf4j 애노테이션을 이용해 바로 log 사용이 가능하다.

 

로그 레벨 설정

application.properties

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

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

 

위의 파일에서 logging.level.hello.springmvc=trace를  추가해 주어야 아래와 같이 trace 로그까지 기록에 남는다.

*설정하지 않을 시 기본 값인 info까지만 호출

 

올바른 로그 사용법

1) log.debug("data=" + data)
    → 로그 출력 레벨을 info로 설정해도 해당 코드에 있는 "data="+data가 실제 실행이 되어 문자를 더하는 연산이 발생한다.
2) log.debug("data={}, data)
    → 로그 출력 레벨을 info로 설정하면 아무일도 발생하지 않아 위와 같은 의미없는 연산이 발생하지 않는다.

 

의미 없는 연산이 발생하지 않도록 2번째 방법과 같이 로그를 사용해야 한다 ‼️

 

로그 사용시 장점

  1. 쓰레드 정보, 클래스 이름 같은 부가 정보를 함께 볼 수 있고, 출력 모양을 조정할 수 있다.
  2. 로그 레벨에 따라 개발 서버에서는 모든 로그를 출력하고, 운영 서버에서는 출력하지 않는 등 로그를 상황에 맞게 조절할 수 있다.
  3. 시스템 아웃 콘솔에만 출력하는 것이 아니라, 파일이나 네트워크 등 로그를 별도의 위치에 남길 수 있다.
    특히 파일로 남길 때는 일별, 특정 용량에 따라 로그를 분할하는 것도 가능하다.
  4. 성능도 일반 System.out 보다 좋다. (내부 버퍼링, 멀티 쓰레드 등등)
  5. 따라서 ! 실무에서는 꼭 로그를 사용해야 한다.