본문 바로가기

항해 99/Spring

LogBack을 통한 로그 관리

로깅을 하는 이유

로깅 : 시스템이 동작할 때 시스템의 상태 및 동작 정보를 시간 경과에 따라 기록하는 것을 의미한다.

 

로깅을 통해 할 수 있는 것

  • 개발 과정 혹은 개발 후에 발생할 수 있는 예상치 못한 애플리케이션 문제를 진단할 수 있다
  • 다양한 정보를 수집할 수 있다
  • 사용자 로그의 경우 분석 데이터로도 활용할 수 있다
Reference
https://tecoble.techcourse.co.kr/post/2021-08-07-logback-tutorial/

 

로거 선택 기준

가장 많이 사용되는 로거

  • Logback
  • java.tuil.logging
  • Log4j2

Log Back의 성능이 전반적으로 가장 탁월하기 때문에 대체로 LogBack을 선택했다.

 

Log Back이란?

Slf4j의 구현체로 Spring Boot 환경이라면 별도의 dependency 추가 없이 기본적으로 포함되어 있음

Logback은 Log4j에 비해 향상된 필터링 정책, 기능, 로그 레벨 변경 등에 대해 서버를 재시작할 필요 없이 자동 리로딩을 지원한다는 장점을 가진다.

 

로그 레벨

fatal : 아주 심각한 에러가 발생한 상태를 나타냄

Error : 예상하지 못한 심각한 문제가 발생하는 경우

Warn : 로직 상 유효성 확인, 예상 가능한 문제로 인한 예외 처리

Info : 운영에 참고할만한 상항

Debug : 개발 단계에서 사용하며 SQL 로깅을 할 수 있다

Trace : 모든 레벨에 대한 로깅이 추적(개발단계에서 사용)

 

로그의 레벨은 5가지이며 심각도 수준은 아래와 같음

Error -> Warn -> Info -> Debug -> Trace

 

로그 레벨을 Info로 설정 시, Info 레벨 이상의 로그레벨(Warn, Error)만 출력된다.

 

※ Debug와 Trace 레벨은 많은 양의 로그가 쌓이기 때문에 개발 단계에서만 사용하고 배포 단계에서는 사용 금지

  • 많은 양의 로그가 쌓이기 때문에 용량 문제가발생할 수 있음

 

xml 설정

appender : 전달받은 로그를 어디에 출력할지 결정함(콘솔 출력, 파일 저장, 데이터베이스 저장 등)

encoder : appender에 포함되어 출력할 로그의 형식을 지정

logger : 로그를 출력하는 요소로, level 속성을 통해 출력할 로그의 레벨을 조절하여 appender에 전달함(첫 번째 logger에서 com.study는 java 디렉토리의 Java 패키지 경로를 의미함)

 

로그 타입

sqlonly : SQL을 로그로 남기며, Prepared Statement와 관련된 파라미터는 자동으로 변경되어 SQL을 출력함

sqltiming : SQL과 SQL 실행 시간(milliseconds 단위)을 출력합니다.

audit : ResultSet을 제외한 모든 JDBC 호출 정보를 출력합니다. JDBC 관련 문제를 추적하는 경우를 제외하고는 사용이 권장되지 않음

resultset : ResultSet을 포함한 모든 JDBC 호출 정보를 출력함

resultsettable : SQL 조회 결과를 테이블 형태로 출력함

connection : Connection의 연결과 종료에 관련된 로그를 출력함, 커넥션 누수 문제 해결에 도움이 됨

 

파일 지정

파일 속성

 

로그백 설정 방법

Springboot 환경이라면 별도의 설정 없이 사용이 가능하다.

 

로그 관련 설정 방법은 application.yml과 logback-spring.xml 에서 설정하는 방법이 있다.

 

application.yml은 기본 설정 난이도가 비교적 쉽지만, 세부적인 설정이 불편하기 때문에 logback-spring.xml로 관리하는 편이 더 좋음

 

logback-spring.xml으로 로그를 기록

resource 패키지에 logback-spring.xml을 생성한다.

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
		<!-- base.xml default.xml 에 존재하는 Log 메시지의 Color 설정 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
		
	<!-- 콘솔에 출력되는 로그 패턴 -->
    <property name="CONSOLE_LOG_PATTERN"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %clr(%5level) %cyan(%logger) - %msg%n"/>
		<!-- Log파일에 기록되는 로그 패턴 -->
    <property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %5level %logger - %msg%n"/>
		
	<!-- 콘솔로그 Appender -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>
		
	<!-- 파일로그 Appender -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>
		<!-- RollingPocliy: 로그가 길어지면 가독성이 떨어지므로 로그를 나눠서 기록하기위한 규칙 -->
		<!-- 로그파일을 크기, 시간 기반으로 관리하기 위한 SizeAndTimeBasedRollingPolicy -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
			<!-- 로그파일명 패턴 -->
			<!-- 날짜별로 기록되며 maxFileSize를 넘기면 인덱스(i)를 증가시켜 새로운 이름의 로그파일에 기록을 이어간다 -->
            <fileNamePattern>./log/%d{yyyy-MM-dd}.%i.log</fileNamePattern>
			<!-- 로그파일 최대사이즈 -->
            <maxFileSize>100MB</maxFileSize>
			<!-- 생성한 로그파일 관리 일수 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
    </appender>

	<!-- local Profile에서의 로그 설정 -->
    <springProfile name="local">
		<!-- 해당 패키지의 로그는 DEBUG 레벨 부터 출력 -->
        <logger name="com.chiwawa.lionheart" level="DEBUG" />
		<!-- 전체적인 로그는 INFO 레벨 부터 출력 -->
        <root level="INFO">
			<!-- CONSOLE 로그 Appender를 로그 Appender로 등록 -->
            <appender-ref ref="CONSOLE" />
        </root>
    </springProfile>
	<!-- dev Profile에서의 로그 설정 -->
    <springProfile name="dev">
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="FILE" />
        </root>
    </springProfile>
	<!-- prod Profile에서의 로그 설정 -->
    <springProfile name="prod">
        <root level="INFO">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="FILE" />
        </root>
    </springProfile>

</configuration>

 

 

logback.ColorConverter

<property name="CONSOLE_LOG_PATTERN"
      value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %clr(%5level) %cyan(%logger) - %msg%n"/>
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %5level %logger - %msg%n"/>

 

clr로 설정된 converterClass org.springframework.boot.logging.logback.ColorConverter는 logback의 defaults.xml에 설정된 로그 색상 입력 컨버터임

 

defaults.xml에는 로그 패턴들이 관리되고 있으며, CONSOLE_LOG_PATTERN에 적용된 컬러가 clr로 되어 있음을 알 수 있음

 

원래 Log에 색상을 입히려면 %색상코드 와 같은 형태로 입력이 필요한데, 해당 Converter를 가져와 %clr로 설정해주면 로그에 맞는 색상이 자동으로 추가됨

 

Log Pattern

LOG_PATTERN 들은 출력할 로그의 패턴을 설정해놓은 property들로 FILE_LOG_PATTERN에는 색상을 적용하지 않음(색 적용 시 색상코드로 인해 로그가 지저분 해짐)

 

Pattern

로그 출력하기 위해서 어떠한 포맷을 정의할 수 있다.

 

패턴에 사용되는 요소

  • %Logger{length} - Logger name을 축약할 수 있다. {length}는 최대 자리 수
  • %thread - 현재 Thread 이름
  • %-5level - 로그 레벨, -5는 출력의 고정폭 값
  • %msg - 로그 메시지 (=%message)
  • %n - new line
  • ${PID:-} - 프로세스 아이디
  • %d : 로그 기록시간
  • %p : 로깅 레벨
  • %F : 로깅이 발생한 프로그램 파일명
  • %M : 로깅이 발생한 메소드의 이름
  • %l : 로깅이 발생한 호출지의 정보
  • %L : 로깅이 발생한 호출지의 라인 수
  • %t : 쓰레드 명
  • %c : 로깅이 발생한 카테고리
  • %C : 로깅이 발생한 클래스 명
  • %m : 로그 메시지
  • %r : 애플리케이션 시작 이후부터 로깅이 발생한 시점까지의 시간

 

Appender

로그의 형태를 설정하며, 로그 메시지를 콘솔에 출력할지, 파일에 출력할지 등의 설정을 통해 출력될 대상을 결정하는 요소로, 로그 출력 방식 관리자

<!-- 콘솔로그 Appender -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
        </encoder>
    </appender>
		
		<!-- 파일로그 Appender -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>${FILE_LOG_PATTERN}</pattern>
        </encoder>
				<!-- SizeAndTimeBasedRollingPolicy: 로그파일을 크기, 날짜 기반으로 관리하기 위한 롤링 정책 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
						<!-- 로그파일명 패턴 -->
						<!-- 날짜별로 기록되며 maxFileSize를 넘기면 인덱스(i)를 증가시켜 새로운 이름의 로그파일에 기록을 이어간다 -->
            <fileNamePattern>./log/%d{yyyy-MM-dd}.%i.log</fileNamePattern>
						<!-- 로그파일 최대사이즈 -->
            <maxFileSize>100MB</maxFileSize>
						<!-- 생성한 로그파일 관리 일수 -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
    </appender>

 

appender에서 자주 사용하는 것

 

ConsoleAppender

  • ConsoleAppender는 로그를 OutputStream에 작성하여 콘솔에 출력

FileAppender

  • fileAppender는 파일에 로그를 출력하며, 최대 보관 일수, 파일 용량 등을 지정 가능
  • RollingFileAppender는 FileAppender를 상속 받으며, 여러 개의 파일을 롤링, 순회하면서 로그를 파일에 출력한다
  • SizeAndTimeBasedRollingPolicy에 의해 지정된 용량이 넘어간 로그 파일을 넘버링하여서 나눠서 저장이 가능

 

Profile 설정

profile에 따른 로그 관리 설정 코드이다

<springProfile name="local">
			<!-- 해당 패키지의 로그는 DEBUG 레벨 부터 출력 -->
    <logger name="com.chiwawa.lionheart" level="DEBUG" />
			<!-- 전체적인 로그는 INFO 레벨 부터 출력 -->
    <root level="INFO">
					<!-- CONSOLE 로그 Appender를 Appender로 등록 -->
        <appender-ref ref="CONSOLE" />
    </root>
</springProfile>

	<!-- dev Profile에서의 로그 설정 -->
<springProfile name="dev">
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
</springProfile>

	<!-- prod Profile에서의 로그 설정 -->
<springProfile name="prod">
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
        <appender-ref ref="FILE" />
    </root>
</springProfile>

 

운영서버는 저장공간 성능 측면을 많이 봐야하기 때문에 로그를 다른 환경에서 보다 효율적으로 관리해야 할 필요가 있음

 

 

로그 찍는 방법

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

@RestController
public class LogController {

    private final Logger logger = LoggerFactory.getLogger("LoggerController 의 로그");

    @GetMapping("/log")
    public void log() {
        logger.info("로깅 발생!");
    }
}
  • 코드에 로그를 추가하고 SpringApplication을 실행한 후 설정한 API를 호출한다(localhost:8080/log)
  • 콘솔에 출력된 로그를 확인한다
[2021-08-07 18:03:03:7491][http-nio-8080-exec-1] INFO  LoggerController 의 로그 - 로깅 발생!
  • Info 레벨 로그로 "LoggerControllerd의 로그 - 로깅 발생!"이 콘솔에 출력되는 것을 확인할 수 있음

 

에러 레벨에 따른 로깅 결과

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LogController {

    @Autowired
    private LogService logService;

    @GetMapping("/log")
    public void log() {
        logService.log();
    }
}

 

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class LogService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());

    public void log() {
        logger.trace("Trace");
        logger.debug("Debug");
        logger.info("Info");
        logger.warn("Warn");
        logger.error("Error");
    }
}

 

위 두 파일을 실행 후 localhost:8080/log에 접속하고 콘솔에 출력된 내용을 살펴본다.

[2021-08-07 18:19:09:17317][http-nio-8080-exec-1] INFO  LogService - Info
[2021-08-07 18:19:09:17317][http-nio-8080-exec-1] WARN  LogService - Warn
[2021-08-07 18:19:09:17317][http-nio-8080-exec-1] ERROR LogService - Error
  • 로그는 별다른 설정을 하지 않아도 기본 설정된 로그 레벨(INFO)에 맞춰 상위 로그로 출력됨

 

Reference

https://velog.io/@pgmjun/LogBack%EC%9D%84-%ED%86%B5%ED%95%9C-%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9D%B8-%EB%A1%9C%EA%B7%B8-%EA%B4%80%EB%A6%AC

https://tecoble.techcourse.co.kr/post/2021-08-07-logback-tutorial/

https://congsong.tistory.com/23

 

'항해 99 > Spring' 카테고리의 다른 글

CORS  (1) 2024.03.18
AWS로 HTTPS 연결  (0) 2024.03.16
Jwt Access Token과 Refresh Token  (0) 2024.03.14
REST API URI 규칙  (0) 2024.03.13
ExceptionHandler  (0) 2024.03.11