스프링 부트의 Logging(로깅) 라이브러리

Daniel·2024년 11월 21일
0

Back-End

목록 보기
43/48

들어가며

log4j, log4j2, slf4j, logback 다 로깅과 관련된 단어다.
국비충 백엔드 웹 개발자로 일하며 로깅에 대해서는 log. 찍으면 되는거아니야? 라고 생각했는데
이번 프로젝트에서 제대로 사용해보며 정리하고 넘어가야겠다 싶어 이 포스트를 작성합니다.

스프링 환경에서의 로깅

초창기 스프링 프레임워크는 JCL(Jakarta Commons Logging) 을 사용해서 로깅을 구현했다.
그 이유 중 하나는 스프링 프레임워크의 PSA(Portable Service Abstraction) 때문인데,
JCL을 사용하면 기본 인터페이스인 Log 와 Log 객체 생성을 담당하는 LogFactory만 구현 하는 것으로 언제든 로깅 구현체 교체가 가능하기 때문이다.

JCL은 LogFactory를 통해 불러온 로깅 구현체를 런타임 시점에 로딩하여 사용하는 방식이다.
아래와 같은 설정으로 사용한다.

public class SampleClass { 
	Logger log = LoggerFactory.getLogger(this.getClass().getName()); 
	
	public void sampleMethod() { 
		log.info("This is an logging message"); 
		// ... 
	} 
}

현재는 SLF4j 라는 새로운 로깅 인터페이스 기반의 구현체를 사용한다. Logback, Log4j2 등이 대표적이다.
SLF4JJCL 의 런타임 로딩 문제 해결을 위해 컴파일 시점에 구현체를 선택하도록 변경시키기 위해 도입되었다.
SLF4J 인터페이스는 JCL보다 더 심플해서, Log와 LogFactory를 구현할 필요도 없다. 롬복(Lombok)과 함께 사용하면 위 코드는 아래와 같이 단순화된다.

@Slf4j 
public class SampleClass {
	private void init() {
		log.info("Sample Class is initialized!!!"); 
	} 
}

다만 SLF4j 구현체들은 JCL 인터페이스를 구현하지 않으므로 JCL 환경에서 바로 사용할 수 없으며, JCLSLF4j 사이를 연결하는 어댑터를 필요로 한다. Logback, Log4j2를 사용하기 위해 스프링 부트가 jcl-over-slf4j 라이브러리에 의존성을 가지는 이유이다. 이를 도식화한 형태는 다음과 같다.

System.out.println() 와의 차이점

System.out.println() 로 출력된 로그는 콘솔에만 나타나며, 프로그램이 종료되면 이 정보는 사라집니다.
따라서 로그가 발생한 날짜, 시간, 로그 발생 위치 와 같은 추적 정보를 기록하지 않기 때문에 문제의 원인을 파악하고 해결할 수 없습니다.

Log 는 콘솔, 파일, DB 등 여러 대상에 출력할 수 있습니다.
로그 레벨 을 사용해 로그 중요도에 따라 메시지를 구분할 수 있어, 에러나 장애 발생 시 필요한 정보를 파악하기 용이합니다.

하지만 System.out.print()와 같은 출력된 로그는 휘발성으로 로그 레벨에 따른 로깅이 불가능합니다.

만약 로그 레벨을 관리 없이 System.out.print를 통해 출력되는 모든 로그 정보가 파일에 저장될 경우 중요도가 낮은 정보까지 모두 파일에 저장되어 서버의 저장 공간을 불필요하게 사용할 수 있습니다. 특히 대규모 시스템이나 장기간 운영되는 서비스에서는 이러한 불필요한 로그 데이터가 상당한 저장 공간을 차지할 수 있으며, 이로 인해 시스템 성능에도 영향을 줄 수 있습니다.

Log4j와 Logback, 그리고 Log4j2

가장 널리 알려진 자바 기반 로깅 프레임워크는 log4j와 logback, 그리고 log4j2이다.
중요한 차이점 중 하나는 log4j는 JCL 인터페이스를 구현하는 반면, logback과 log4j2는 SLF4J 인터페이스를 구현한다는 점이다.
이 때문에 logback이나 log4j2는 JCL 환경에서 바로 사용할 수 없다.
다만 스프링부트에서는 JCL과 SLF4J를 연결하는 어댑터인 jcl-over-slf4j를 기본으로 임포트하고 있으므로, SLF4j 구현체를 로깅 프레임워크로 사용하기 위해 특별히 해줄 것은 없다.

Log4j

Apache에서 가장 먼저 널리 사용되는 로깅 프레임워크 중 하나다.
성능 제한 및 설계 결함으로 인해 더 이상 사용되지 않으며 Log4j2로 대체되었다.

Logback

log4j 이후에 공개된 로깅 프레임워크 중 하나로, SLF4j 의 구현체이다.
스프링 부트 환경이라면 별도의 dependency 추가 없이 사용될 수 있도록 기본 라이브러리로 포함되어 있기 때문에, 현재 가장 널리 사용되고 있는 로깅 프레임워크라고 할 수 있다. Logback은 log4j 에 비해 향상된 필터링 정책, 기능, 로그 레벨 변경 등에 대해 서버를 재시작할 필요 없이 자동 리로딩을 지원하는 등의 장점을 가진다.

Log4j2

Log4j의 후속 버전으로, SLF4j의 구현체이다. 스프링 부트에 기본 탑재되어 있지 않으므로 기존의 Log4j나 Logback 라이브러리를 걷어내고 그 자리에 대신 넣어 사용해야 해서 다소 번거롭다. 하지만 Async Appender, Async Logger 등 비동기 옵션을 제공하여 멀티 스레드 하에서 상당한 성능 개선을 보여주므로 대용량 트래픽 하에서는 좋은 선택이 될 수 있다. Log4j2 사용 시에는 최신 버전을 사용하는 것이 좋은데, 이는 2021년에 배포된 특정 버전에서 심각한 보안 결함이 발견되었기 때문이다.

스프링 부트의 기본 로깅 프레임워크 (Logback)

Logback은 log4j를 대신하는 스프링 부트의 공식 로거이다.
스프링부트 스타터(Springboot-Starter)에 기본으로 탑재되어 있으며, SLF4J 의 API 스펙을 구현하고 있다.
다시 말해, 기존의 구현체가 무엇이든 간에 SLF4J API를 사용하고 있었다면, 로깅 구현체를 Logback 으로 변경하더라도 로깅 관련 코드는 수정할 필요가 없다.

스프링부트 + 롬복의 @Slf4j 어노테이션 기반으로 로깅 모듈을 사용하고 있다면 Logback으로의 마이그레이션은 더욱 간단하다. 프로젝트의 build.gradle 또는 pom.xml 파일에서 log4j를 임포트하도록 작성된 부분을 제거하기만 하면 된다.

최신 버전의 스프링 부트를 사용 중이라면 Logback은 spring-boot-starter 라이브러리에 이미 포함되어 있다.
따라서 Logback을 적용하기 위해서 아무 것도 하지 않아도 된다.

Log4j2

Log4j2 는 Apache에서 서포트하는 가장 최신의 로깅 프레임워크로, Log4jLogback 의 문제점을 개선하고 Log4j 의 성능을 향상하기 위해 만들어졌다. Logback 과 마찬가지로 SLF4J 를 기본적으로 지원하고, 로깅 설정 자동 새로고침, 향상된 필터 옵션을 지원한다. 람다식에 기반하여 로그 상태의 lazy evaluation을 지원하며, low-latency를 위한 비동기 로깅을 제공한다. 또한 GC 작동에 의해 발생하는 지연을 피하기 위한 garbage-free mode도 제공한다.

logback 과의 차이점

  • XML, groovy 로 구성가능한 logback 과는 달리 XML, JSON, YAML 구성 형식을 지원한다.
  • logback 과는 달리 별도의 의존성 주입이 필요하다.
  • log4j2 는 비동기 로거(별도의 스레딩 모델) 를 통해 성능이 더 높다.
  • 처리량이 많을 때는 log4j2 를 사용하는게 더 적합하다.
profile
응애 나 애기 개발자

0개의 댓글