[Spring] 로깅 라이브러리 - Logback

Miin·2023년 10월 30일
0

Spring

목록 보기
7/17
post-custom-banner

로깅(logging)이란?

애플리케이션이 동작하는 동안 시스템의 상태나 동작 정보를 시간순으로 기록하는 것.

개발 영역 중 '비기능 요구사항' (사용자나 고객에게 필요한 기능은 아니라는 뜻)
하지만 로깅은 디버깅하거나 개발 이후 발생한 문제를 해결할 때 원인을 분석하는 데 꼭 필요한 요소이다.

자바 진영에서 가장 많이 사용되는 로깅 프레임워크는 Logback이다.

Logback이란?

📌 log4j 이후에 출시된 로깅 프레임워크로서 slf4j를 기반으로 구현됐으며, 과거에 사용되던 log4j에 비해 성능이 월등하다. 스프링 부트의 spring-boot-starter-web 라이브러리 내부에 내장되어 있어 별도의 의존성을 추가하지 않아도 사용 가능하다.

Logback의 특징

  • 크게 5개의 로그 레벨(ERROR, WARN, INFO, DEBUG, TRACE) 설정
    - ERROR: 로직 수행 중 시스템에 심각한 문제가 발생해 애플리케이션 작동이 불가능한 경우
    • WARN: 시스템 에러의 원인이 될 수 있는 경고 레벨
    • INFO: 애플리케이션 상태 변경과 같은 정보 전달
    • DEBUG: 애플리케이션 디버깅을 위한 메시지를 표시하는 레벨
    • TRACE: DEBUG 레벨보다 더 상세한 메시지를 표현하기 위한 레벨
  • 실제 운영 환경과 개발 환경에서 각각 다른 출력 레벨을 설정해 로그 확인
  • Logback 설정 파일을 일정 시간마다 스캔해 애플리케이션을 재가동하지 않아도 설정 변경
  • 별도 프로그램 지원 없이 자체적으로 로그 파일 압축
  • 저장된 로그 파일에 대한 보관 기간 등을 설정해 관리

Logback 설정

일반적으로 클래스패스(classpath)에 있는 설정 파일을 자동으로 참조하므로 Logback 설정 파일은 리소스 폴더 안에 생성한다. 파일명의 경우 일반적인 자바 또는 스프링 프로젝트에서는 logback.xml이라는 이름으로 참조하지만 스프링 부트에서는 logback-spring.xml 파일을 참조한다.

  • Logback 설정 파일 예시
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <property name="LOG_PATH" value="./logs"/>  // Property 영역

    <!-- Appenders -->  // Appender 영역
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <encoder>  // Encoder 영역
            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger %msg%n</pattern>  // Pattern 영역
        </encoder>
    </appender>

    <appender name="INFO_LOG"  // Appender 영역 class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <file>${LOG_PATH}/info.log</file>
        <append>true</append>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/info_${type}.%d{yyyy-MM-dd}.gz</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>  // Encoder 영역
            <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger %msg%n</pattern>  // Pattern 영역
        </encoder>
    </appender>

    <!-- TRACE > DEBUG > INFO > WARN > ERROR > OFF -->
    <!-- Root Logger -->  // Root 영역
    <root level="INFO">
        <appender-ref ref="console"/>
        <appender-ref ref="INFO_LOG"/>
    </root>
</configuration>
  • Property 영역
  • Appender 영역
  • Encoder 영역
  • Pattern 영역
  • Root 영역

각 영역 가운데 Logback 설정에서 가장 중요한 Appender 영역과 Root 영역에 대해 좀 더 자세히 알아보자.

Appender 영역

로그의 형태를 설정하고 어떤 방법으로 출력할지 설정하는 곳

Appender 자체는 하나의 인터페이스를 의미, 하위에 여러 구현체 존재

  • Appender의 상속 구조

Logback 설정 파일을 이용하면 그림의 각 구현체를 등록해서 로그를 원하는 형식으로 출력할 수 있다.

Appender의 대표적인 구현체

  • ConsoleAppender: 콘솔에 로그 출력
  • FileAppender: 파일에 로그 저장
  • RollingFileAppender: 여러 개의 파일을 순화하면서 로그 저장
  • SMTPAppender: 메일로 로그 전송
  • DBAppender: 데이터베이스에 로그 저장

로그를 어떤 방식으로 저장할지 지정하는 방법
위 Logback 설정 파일 코드에서 appender 요소의 class 속성에 각 구현체를 정의한다. 그리고 하단에 filter 요소로 각 Appender가 어떤 레벨로 로그를 기록하는지 지정한다.
다음으로 encoder 요소를 통해 로그의 표현 형식을 패턴으로 정의한다.

대표적인 패턴

  • %Logger{length}: 로거의 이름
  • %-5level: 로그 레벨, -5는 출력 고정폭의 값
  • %msg{%message}: 로그 메시지
  • %d: 로그 기록 시간
  • %p: 로깅 레벨
  • %F: 로깅이 발생한 애플리케이션 파일명
  • %M: 로깅이 발생한 메서드 이름
  • %I: 로깅이 발생한 호출지의 정보
  • %thread: 현재 스레드명
  • %t: 로깅이 발생한 스레드명
  • %c: 로깅이 발생한 카테고리
  • %C: 로깅이 발생한 클래스명
  • %m: 로그 메시지
  • %n: 줄바꿈
  • %r: 애플리케이션 실행 후 로깅이 발생한 시점까지의 시간
  • %L: 로깅이 발생한 호출 지점의 라인 수

로그 형식 예

<pattern>[%d{yyyy-MM-dd HH:mm:ss, SSS}] [%-5level] [%thread] %logger %msg%n</pattern>

Root 영역

설정 파일에 정의된 Appender를 활용하려면 Root 영역에서 Appender를 참조해 로깅 레벨을 설정한다. 만약 특정 패키지에 대해 다른 로깅 레벨을 설정하고 싶다면 root 대신 logger를 사용해 다음과 같이 지정할 수 있다.

	<root level="INFO">
        <appender-ref ref="console"/>
        <appender-ref ref="INFO_LOG"/>
    </root>
    
    또는
    
    <logger name="com.springboot.api.controller" level="DEBUG" additivity="false">
    	<appender-ref ref="console"/>
        <appender-ref ref="INFO_LOG"/>
    </logger>

name 속성: 패키지 단위로 로깅이 적용될 범위 지정
level 속성: 앞에서 지정한 패키지 범위에 하위 패키지 포함 여부 결정. 기본값 true(하위 패키지 모두 포함)


Logback 적용

Logback은 출력할 메시지를 Appender에게 전달할 Logger 객체를 각 클래스에 정의해 사용한다.

private final Logger LOGGER = (Logger) LoggerFactory.getLogger(GetController.class);

클래스의 LOGGER 전역 변수로 Logger 객체를 정의해 주고,

다음과 같이 로그를 출력하는 코드를 삽입해주면 된다.

	// http://localhost:8080/api/v1/get-api/hello
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String getHello() {
        LOGGER.info("getHello 메서드가 호출되었습니다.");
        return "Hello World";
    }

❗❗이렇게 하면 콘솔 화면에 로그가 출력되는데, 오류가 발생하여 @Slf4j 어노테이션을 이용하여 다음과 같이 코드를 수정해주었다.

@Slf4j
@RestController
@RequestMapping("/api/v1/get-api")
public class GetController {

    // http://localhost:8080/api/v1/get-api/hello
    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String getHello() {
        log.info("getHello 메서드가 호출되었습니다.");
        return "Hello World";
    }

그러면 다음과 같이 콘솔에 로그가 출력되는 것을 볼 수 있다.

[2023-10-29 19:53:20.081] [INFO ] [http-nio-8080-exec-1] com.springboot.api.controller.GetController getHello 메서드가 호출되었습니다.

로그를 통해 컨트롤러에 들어오는 값을 확인하고 싶다면 다음과 같이 코드를 작성하면 된다. 변수를 지정해 변수로 들어오는 값을 로깅한다. 변수의 값이 들어갈 부분을 {중괄호}로 지정하면 포매팅을 통해 로그 메시지가 구성된다.
	// http://localhost:8080/api/v1/get-api/variable1/{String 값}
    @GetMapping(value = "/variable1/{variable}")
    public String getVariable1(@PathVariable String variable) {
        log.info("@PathVariable을 통해 들어온 값: {}", variable);
        return variable;
    }

메서드를 통해 String 값으로 Corner를 주고 호출하면 다음과 같은 출력 결과가 나온다.

[2023-10-29 19:59:10.335] [INFO ] [http-nio-8080-exec-8] com.springboot.api.controller.GetController @PathVariable을 통해 들어온 값: Corner



[출처] 책 스프링 부트 핵심 가이드 (장정우), 위키북스

profile
컴퓨터공학전공 학부생 Back-end Developer
post-custom-banner

0개의 댓글