[Spring Boot] Logging

diense_kk·2023년 10월 31일
0

SpringBoot

목록 보기
7/10
post-thumbnail

왜 편하게 표준 출력이 가능한 System.out.println() 메소드를 놔두고 사람들은 로깅 프레임워크를 사용하는 것 일까? 더 나아가 왜 System.out.println() 을 프로덕션 코드에서 사용하면 안되는 것 일까?

휘발된다

System.out.println() 은 로그가 표준 출력으로 출력된다. 즉, 파일로 저장되지 않고 휘발된다는 의미이다. 로그는 에러가 발생한 상황을 기록하고, 추후 확인하여 문제를 진단하고, 재현하고, 고치기 위해 사용된다. 하지만 표준 출력으로 한번 출력되고 어디에도 저장되지 않으면 로그의 제 역할을 할 수 없다.

로그된 데이터는 실제로 기록되어야 한다. 하지만 System.out.println() 만으로는 불가능하다.

에러 발생 시 추적할 수 있는 최소한의 정보가 남지 않는다

System.out.println() 은 인자로 전달한 문자열만을 출력한다. 문제가 발생한 날짜, 시각 그리고 문제의 수준, 로그가 발생한 위치 등 최소한의 정보가 기록되지 않는다는 것 이다. 이런 제한적인 정보만으로는 문제를 해결하기 어려울 것 이다.

성능저하의 원인이 될 수 있다

System.out.println() 의 구현을 한번 살펴보자.

public void println() {
    newLine();
}

println() 은 newLine() 을 호출한다. newLine() 의 구현도 살펴보자.

private void newLine() {
    try {
        synchronized (this) {
            ensureOpen();
            textOut.newLine();
		// ...

synchronized 키워드가 붙어있다. 이때 newLine() 메소드는 임계영역(critical section)이 된다. 멀티 쓰레드 환경에서 A 쓰레드가 newLine() 메소드를 실행하면, 메소드는 잠기게 된다. 다른 쓰레드는 A 쓰레드가 모두 사용하고 잠금을 풀어준 뒤에서야 newLine() 메소드를 실행할 수 있다. 오버헤드가 발생하게 되는 것 이다.

스프링을 실행하는 톰캣은 멀티 쓰레드로 동작한다. 요청이 오면 쓰레드 풀에서 쓰레드를 하나 가져와 요청을 처리한다. 그런데, System.out.println() 을 여러 쓰레드가 사용하면 그만큼 위에서 이야기한 오버헤드가 발생하고 처리가 느려질 것 이다. 따라서 실제 프로덕트의 코드에서는 System.out.println() 을 절대 사용해서는 안된다.

Logging 라이브러리 종류

Log4J

굉장히 오래된 로깅 라이브러리.
2015년 8월 5일 이후 지원이 종료되어 사용하지 않는다.

Logback

Log4J 이후 출시된 보다 향상되고 가장 널리 사용되는 라이브러리.
필터링 기능과 자동 리로딩을 지원한다.
SLF4J의 구현체로써 동작하며, 스프링 부트에서 기본으로 사용된다.

Log4J2

가장 최신에 나온 라이브러리이며, Apache Log4J의 다음 버전이다.
필터링 기능과 자동 리로딩을 지원한다.
SLF4J의 구현체이다.
멀티 쓰레드 환경에서 비동기 로거( Async Logger )의 경우
다른 Logging 프레임워크보다 처리량이 많고, 대기시간이 짧다.
Java Lambda를 지원한다.

SLF4J

로깅 통합 인터페이스
스프링 부트에서 로깅을 구현할 때 사용된다.
코드의 변경 없이 설정만 변경하는 것으로 다른 로깅 라이브러리로 변경할 수 있게 도와준다.
프로그래머는 SLF4J를 이용해 코드를 작성하고,
SLF4J는 컴파일 시점에 등록된 구현체 라이브러리( Logback )를 바인딩하여 동작한다.

Logging의 장점

Thread 정보, Class 이름 같은 부가 정보를 함께 볼 수 있고, 출력 모양을 정할 수 있다.
로그 레벨에 따라 개발 서버에서는 모든 로그를 출력하고, 운영 서버에서는 출력하지 않는 등, 로그를 상황에 맞게 조절할 수 있다.
콘솔에만 출력하는 것이 아닌, 파일이나 네트워크 등 별도의 위치에 남길 수 있다.
비동기로 동작한다.

사용법

로그 선언

private Logger log = LoggerFactory.getLogger(getClass());
private static final Logger log = LoggerFactory.getLogger(Xxx.class);
@Slf4j ( Lombok )

로그 호출

log.info("hello");
log.info("value = {}", value);

로그 단계

trace > debug > info > warn > error > fatal
설정된 로그 레벨에 따라 순위에 맞춰 출력되거나 무시된다.
예를 들어 info level로 설정되어 있으면, trace, debug level은 무시된다.

로그 레벨 설정

application.properties

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

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

0개의 댓글