본문 바로가기

Project/날씨 기반 여행 플래너

[날씨 기반 여행 플래너] 로깅 전략

작년 11월, 멀티캠퍼스에서 백엔드 개발 교육 과정을 수료했다.

 

최종 프로젝트를 진행하면서 마주했던 문제들을 노션에 정리해놨는데,

프로젝트 복기 겸..! 누군가에게 도움이 될까 싶어..! 글로 정리해보고자 한다.

 

프로젝트를 간단히 설명하자면, '날씨 기반 여행 플래너'로 날씨를 바탕으로 여행 계획을 수립할 수 있는 웹 서비스이다.

Java, Spring boot, MyBatis, Oracle 등의 기술을 활용하였고,

날씨와 여행 장소 데이터는 기상청과 한국관광공사의 Open API를 이용하였다.

 

 


 

프로젝트 당시 세웠던 로깅 전략에 관해 얘기해보려고 한다 !

 

로그에 대해 무지했던 나는 모든 패키지에 debug 레벨로 설정하여 사용했다.

하지만, 이 설정은 모든 라이브러리, 프레임워크의 내부 동작을 콘솔에 출력해주었고,

이는 서비스의 흐름이나 발생한 에러를 파악하기 힘들었다... 매우매우

 

또한, 콘솔의 버퍼 사이즈가 작아 로그가 지워지고,

애플리케이션을 다시 시작했을 때 로그가 지워지는 문제로

이전에 발생했던 에러를 확인하고 싶을 때 그러지 못하는 점이 아쉬웠다.

 

설정하는 데 시간이 소요될까 미뤘던 일이지만,

장기적으로 봤을 때 로그 분석 시간을 확실히 줄여줄 것 같아 로깅 설정을 하기로 마음먹었다 !

 

당시 로깅 전략은 로컬 환경, 개발 환경을 나눠서 세웠다.

로컬 환경은 각자 공간이기에 로그를 자유롭게 남겨도 되지만,

개발 환경은 모든 팀원이 함께 애플리케이션을 테스트하는 공간이기에

개인적으로 남긴 로그는 혼란을 줄 수 있기 때문이다.

 

일단 공통적으로 "org.springframework" 패키지는 info 레벨 이상으로 두면서

중요한 로그(info, warn, error)만 남겼다.

 

그리고 애플리케이션의 패키지는 로컬 환경에서 debug 레벨 이상,

개발 환경에선 info 레벨 이상으로 두었다.

 

애플리케이션의 주요 동작은 info로그로 남김으로써,

애플리케이션의 흐름(로그인 -> 여행 일정 저장 -> 에러)을 실시간으로 알 수 있도록

콘솔에 출력해주었다. (처음에는 파일에 출력했지만, 파일을 계속 열어야 하는 불편함이 있었다.)

그리고 다시 확인하기 용이하도록 같은 로그를 파일에도 출력할 수 있도록 해주었다.

 

또한, 에러만 볼 일이 있을 것 같아 warn 레벨 이상의 로그를 또다른 파일에 출력하도록 하였다.

 

정리하자면,

로컬 환경에는 콘솔, 파일1에 디버깅, HTTP 요청/응답, 에러 로그가 기록되고, 파일 2에는 에러 로그가 기록된다.

개발 환경에는 콘솔, 파일1에 HTTP 요청/응답, 에러 로그가 기록되고, 파일 2에는 에러 로그가 기록된다.

 

[ 콘솔 설정 ]

  • 로컬 환경에서 애플리케이션은 debug 레벨 이상의 로그가 콘솔에 출력해야 하기 때문에 CONSOLE appender는 filter를 두지 않았다.
  • 프레임워크는 info 레벨 이상의 로그가 콘솔에 출력해야 하기 때문에 CONSOLE-INFO appender는 level을 INFO로 두었다.
  • ThresholdFilter는 설정된 로그 레벨 이상의 모든 로그 이벤트를 허용한다.
<property name="CONSOLE_LOG_PATTERN"
              value="%clr(%5level) %cyan(%logger) %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread]%n %msg %n%n"/>

<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
  <encoder>
    <pattern>${CONSOLE_LOG_PATTERN}</pattern>
  </encoder>
</appender>

<appender name="CONSOLE-INFO" class="ch.qos.logback.core.ConsoleAppender">
  <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
    <level>INFO</level>
  </filter>
  <encoder>
    <pattern>${CONSOLE_LOG_PATTERN}</pattern>
  </encoder>
</appender>

<springProfile name="local">
  <logger name="org.springframework" level="DEBUG" additivity="false">
    <appender-ref ref="CONSOLE-INFO"/>
    <appender-ref ref="FILE-FLOW"/>      
    <appender-ref ref="FILE-WARN"/>
  </logger>

  <logger name="com.olaenmanijo.weatherbasedtravelplanner" level="DEBUG" additivity="false">
    <appender-ref ref="CONSOLE" />
    <appender-ref ref="FILE-FLOW"/>
    <appender-ref ref="FILE-WARN"/>
  </logger>
</springProfile>


<springProfile name="dev">
  <logger name="org.springframework" level="INFO" additivity="false">
    <appender-ref ref="CONSOLE"/>
    <appender-ref ref="FILE-FLOW"/>     
    <appender-ref ref="FILE-WARN"/>
  </logger>

  <logger name="com.olaenmanijo.weatherbasedtravelplanner" level="INFO" additivity="false">
     <appender-ref ref="CONSOLE" />
     <appender-ref ref="FILE-FLOW"/>
     <appender-ref ref="FILE-WARN"/>
  </logger>
 </springProfile>

 

 

[ 파일1 설정 ]

  • debug 레벨의 로그는 파일에 기록되지 않도록 하였다.
  • 애플리케이션, 프레임워크 모두 info 레벨 이상의 로그만 기록된다.
  • 파일 크기를 제한하지 않으면 디스크 공간을 많이 잡아먹기에 총용량이 1GB에 도달하면 오래된 로그를 삭제하도록 설정하였다.
  • 한 파일이 너무 커도 로그를 보기 힘들기에 maxFileSize를 50MB로 두어 여러 개의 파일이 생기도록 설정하였다.
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %5level %logger - %msg%n"/>

<appender name="FILE-FLOW" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
    <level>INFO</level>
  </filter>
  <encoder>
    <pattern>${FILE_LOG_PATTERN}</pattern>
    </encoder>
      <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <fileNamePattern>./log/weather-planner-flow-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
        <maxFileSize>50MB</maxFileSize>
        <maxHistory>30</maxHistory>
        <totalSizeCap>1GB</totalSizeCap>
      </rollingPolicy>
</appender>

<springProfile name="local">
  <logger name="org.springframework" level="DEBUG" additivity="false">
    <appender-ref ref="CONSOLE-INFO"/>
    <appender-ref ref="FILE-FLOW"/>     
    <appender-ref ref="FILE-WARN"/>
  </logger>

  <logger name="com.olaenmanijo.weatherbasedtravelplanner" level="DEBUG" additivity="false">
    <appender-ref ref="CONSOLE" />
    <appender-ref ref="FILE-FLOW"/>
    <appender-ref ref="FILE-WARN"/>
  </logger>
</springProfile>


<springProfile name="dev">
  <logger name="org.springframework" level="INFO" additivity="false">
    <appender-ref ref="CONSOLE"/>
    <appender-ref ref="FILE-FLOW"/>      
    <appender-ref ref="FILE-WARN"/>
  </logger>

  <logger name="com.olaenmanijo.weatherbasedtravelplanner" level="INFO" additivity="false">
     <appender-ref ref="CONSOLE" />
     <appender-ref ref="FILE-FLOW"/>
     <appender-ref ref="FILE-WARN"/>
  </logger>
 </springProfile>

 

 

[ 파일2 설정 ]

  • warn 레벨 이상의 로그만 기록된다.
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %5level %logger - %msg%n"/>

<appender name="FILE-WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
  <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
    <level>WARN</level>
  </filter>
  <encoder>
    <pattern>${FILE_LOG_PATTERN}</pattern>
  </encoder>
  <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
    <fileNamePattern>./log/weather-planner-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
    <maxFileSize>50MB</maxFileSize>
    <maxHistory>30</maxHistory>
    <totalSizeCap>1GB</totalSizeCap>
  </rollingPolicy>
</appender>

<springProfile name="local">
  <logger name="org.springframework" level="DEBUG" additivity="false">
    <appender-ref ref="CONSOLE-INFO"/>
    <appender-ref ref="FILE-FLOW"/> 
    <appender-ref ref="FILE-WARN"/>
  </logger>

  <logger name="com.olaenmanijo.weatherbasedtravelplanner" level="DEBUG" additivity="false">
    <appender-ref ref="CONSOLE" />
    <appender-ref ref="FILE-FLOW"/>
    <appender-ref ref="FILE-WARN"/>
  </logger>
</springProfile>


<springProfile name="dev">
  <logger name="org.springframework" level="INFO" additivity="false">
    <appender-ref ref="CONSOLE"/>
    <appender-ref ref="FILE-FLOW"/>    
    <appender-ref ref="FILE-WARN"/>
  </logger>

  <logger name="com.olaenmanijo.weatherbasedtravelplanner" level="INFO" additivity="false">
     <appender-ref ref="CONSOLE" />
     <appender-ref ref="FILE-FLOW"/>
     <appender-ref ref="FILE-WARN"/>
  </logger>
 </springProfile>