LogBack을 통한 효율적인 로그 관리

pgmjun·2023년 9월 21일
11

SpringBoot

목록 보기
2/4
post-thumbnail

🔥 문제 의식

로그 관리를 효율적으로 해야겠다는 생각이 든 건 라이온하트 서버를 개발하는 과정에서였다.

서버 로직을 개발할 땐 크게 문제될 상황이 없었지만, 클라이언트 측에서 API를 연결하는 과정에서 로그를 확인해야하는 경우가 많이 발생했는데 로그 파일 하나에 모든 로그를 전부 기록하여 관리하다보니 다음과 같은 문제를 경험했다.

  1. 원하는 정보를 찾기 굉장히 어려웠고
  2. 정리되지 않은 로그는 이해하기 굉장히 어려웠다.

이러한 이유에 의해 로그를 체계적으로, 그리고 효율적으로 관리하기 위한 방법을 생각했고 서버팀원인 혁준이형의 의견으로 LogBack이라는 것을 알게 되어 학습 및 적용해보았다.

그리고 미래의 나를 위해 그 과정을 간단히 기록해보고자 한다.



📝 로깅을 하는 이유

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

로깅을 통해 개발자는

  • 개발 과정 혹은 개발 후에 발생할 수 있는 예상치 못한 애플리케이션의 문제를 진단할 수 있고
  • 다양한 정보를 수집할 수 있다.
  • 사용자 로그의 경우 분석 데이터로도 활용할 수 있다.

하지만 로깅을 하는 단계에서 적절한 수준의 로그 기록 기준을 잡지 못하면 방대한 양의 로그 파일이 생성되는 문제를 겪거나, 의미 있는 로그를 쌓지 못하는 경우가 발생할 수 있다. 결국 효율적으로 로깅을 하는 방법을 이해하는 것이 중요하다.

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



✅ 로거 선택 기준

가장 많이 사용되는 로거는

  • Logback
  • java.tuil.logging
  • Log4j2

위와 같이 3가지 Logger가 존재하는데,

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



🤔 LogBack이란?

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

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



📌 로그 레벨

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

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

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

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

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

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

Error > Warn > Info > Debug > Trace


레벨은 다음과 같이 동작한다.

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



⚙️ 로그백 설정 방법

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

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

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

따라서 logback-spring.xml 로 로그를 기록해보자.

우선 resources 패키지에 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>

이제부터 해당 xml파일에 대해 설명해보겠다.


💭 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이 뭔데 만들어주는거지?

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 는 파일에 로그를 출력하며, 최대 보관 일수, 파일 용량 등을 지정 가능.
  • RollingFileAppenderFileAppender 를 상속 받으며, 여러 개의 파일을 롤링, 순회하면서 로그를 파일에 출력한다.
  • 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>

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

그렇기에 팀원과의 협의를 바탕으로 운영 서버만의 Appender를 만들어 다르게 관리하는 방법도 생각해보면 좋을 것 같다!



reference

https://lovethefeel.tistory.com/89
https://tecoble.techcourse.co.kr/post/2021-08-07-logback-tutorial/
https://breakcoding.tistory.com/400

profile
하나씩 천천히 깊이있게 쌓아가는 백엔드 개발자 최승준입니다.

1개의 댓글

comment-user-thumbnail
2023년 9월 22일

잘 보고 갑니다 ~!

답글 달기

관련 채용 정보