애플리케이션이 동작하는 동안 발생하는 이벤트(예: 오류, 정보, 경고 등)를 기록하는것을 로깅이라 합니다.
이러한 로그는 나중에 버그를 식별하고 해결하는 데 매우 유용하죠!!
모든 메서드에 로그를 기록하는 대신, 다음과 같은 로깅 전략을 통해 효율적인 로깅을 구현할 수 있습니다.
시작과 종료
: 중요한 비즈니스 로직이나 주요 프로세스의 시작과 종료 시점을 기록조건 분기
: 중요한 조건 분기나 결정이 이루어지는 지점에서 로그를 기록오류 및 예외
: 모든 예외 처리 블록에서 예외 정보를 기록ERROR
: 오류 메시지. 예외가 발생했거나 중요한 문제가 발생했을 때 기록WARN
: 경고 메시지. 큰 문제는 아니지만 주의가 필요한 사항을 기록INFO
: 일반적인 운영 정보를 기록. 애플리케이션의 주요 이벤트를 기록DEBUG
: 개발 중 디버깅 목적으로 사용하는 로그. 상세한 정보가 필요할 때 사용우리는 사실 기본적으로 로깅을 사용하고 있다는 것을 아시나요??
스프링 부트 스타터를 사용하면 기본적으로 Logback
을 사용하여 로깅을 실행합니다.
스프링을 실행시키면 아래의 그림처럼 기본적으로 로그가 찍혀있을을 볼 수 있습니다
기본 로깅이 유용하더라도 우리의 요구 사항을 충족시키기에는
충분하지 않을 수 있기때문에 커스텀해서 사용할 수 있습니다!!!!
그리고 로깅설정만을 따로 할 파일이 필요합니다. → 그래서 XML파일
을 사용합니다.
보통 서버는 디벨롭서버, 스테이징 서버, 프로덕션 3개의 서버로 운영됩니다 (3개의 각각 도메인을 가진 서버)
프로덕션서버
: 실제 서비스되는 서버
스테이징 서버
: 프로덕션 서버와 동일한 내용의 서버 → 스테이징 서버에서 개발이 잘 되었는지 실제 데이터와 정상작동하는지 테스트함
디벨롭 서버
: 개발자들이 실시간 개발하는 서버
그렇다면 각각 서버에서의 로깅 전략은 어떻게 가져가야 할까요??
실제 프로덕션 서버
: 로그는 → INFO 로그가 보이면 보안 취약점입니다. → 실제 운영되는 서버에서는 보이는 로그는 없어야 합니다. (아예 로그가 보이면 안됩니다. 해커가 보고 뚫습니다.)
스테이징 서버
: 실 유저 데이터를 그대로 담기 때문에 INFO, Debug가 보이면 안됩니다. ERROR
는 노출되어도 됩니다. (개발자가 확인하고 잡아야 하기 때문에, 아직 테스트용 서버이기 떄문입니다)
디벨롭 서버
: 로그레벨 INFO 가 보여도 됩니다. (개발과, 디버깅을 할때 사용하는 서버이기 때문에 INFO레벨 이상이 보여도 상관없습니다.)
🛠
SLF4J
simple logging facade for java
다양한 로깅 프레임워크에 대한 추상화(인터페이스) 역할을 하는 프레임워크
단독으로 사용 불가
최종 사용자가 배포시 원하는 구현체를 선택
🛠
Logback
Slf4j의 구현체이며 Log4j를 토대로 만든 프레임워크입니다.
스프링 프레임워크에서도 slf4j와 Logback을 채택해서 사용하고 있습니다.
스프링 부트에서 콘솔 로그의 수준을 변경하는 방법은 → application.properties
, logback-spring.xml
에서 설정할 수 있습니다.
application.properties
에서 로그 수준을 변경할 수 있지만 세세한 설정에 제한이 있어 → logback-spring.xml
로 관리하여 세부적인 설정을 할 수 있습니다.
스프링 부트는 로깅 설정 파일의 네이밍에 관한 규칙을 가지고 있습니다.
스프링 부트가 로딩되는 시점에 로그 설정 파일이 프로젝트 내에 존재하는지 스캔합니다
1. logback-spring.xml
2. logback-spring.groovy
3. logback.xml
4. logback.grooby
등의 파일이 있는지 스캔하고 해당 파일에 정의된 로그 설정을 적용하게 됩니다.
특히 logback-spring.xml
은 Spring Boot에 특화된 설정 파일입니다. 이 파일을 사용하면 Spring Boot의 로깅 확장 기능을 활용할 수 있습니다.
1. Logger
(어떻게 기록할까?)
로깅을 수행하는 주요 객체
로거는 이름을 가지며 주로 패키지 이름 또는 클래스 이름과 일치하게 설정
로거는 계층 구조를 가지는데 ROOT 로거는 모든 로거의 상위 로거
출력레벨: TRACE < DEBUG < INFO < WARN < ERROR
기본레벌은 디버그이다. + 지정된 레벨 이하의 메서드들은 기록되지 않는다
ex) INFO 레벨로 지정한 로거는 INFO < WARN < ERROR만 기록한다
2. Appender
(어디에다 기록할까?)
로그 메시지가 출력될 대상을 결정
- 콘솔에다 출력하는
ConsoleAppender
- 파일로 출력하는
FileAppender
- 여러개의 파일을 순회하며 로그를 저장
RollingFileAppender
- 로그 파일을 일정 크기 또는 시간 간격으로 분할(롤링)
rollingPolicy
: 롤링 정책을 정의- 각 로거는 하나 이상의 Appender에 연결될 수 있습니다.
3. Layout
(encoder)(어떻게 출력할까?)
Appender에 포함되어 사용자가 지정한 형식으로 → pattern을 사용해 표현될 로그 메시지를 변환하는 역할
예시
<encoder>
<!-- 로그 메시지의 형식을 정의하는 패턴 설정 -->
<pattern>
<!-- %d{yyyy-MM-dd HH:mm:ss.SSS}: 로그 기록 시각을 연도-월-일 시:분:초.밀리초 형식으로 표시 -->
[%d{yyyy-MM-dd HH:mm:ss.SSS}]
<!-- %-5level: 로그 레벨을 5자리 고정 폭으로 표시 -->
[%-5level]
<!-- %thread: 로그를 기록한 스레드 이름을 표시 -->
[%thread]
<!-- %logger: 로그를 기록한 로거의 이름을 표시 -->
%logger
<!-- %msg: 로그 메시지를 표시 -->
%msg
<!-- %n: 새로운 줄로 이동 -->
%n
</pattern>
</encoder>
현재 로그는
현재 환경은 local
, develop
, blue
, green
4개의 서버로 나누어져 있고 → 각각의 환경마다 로그를 남기는 방법을 다르게 지정할 수 있습니다.
console-appender.xml (콘솔로그 설정)
<included> <!-- 어떤 appender를 사용할지 추가 (자바에서 import와 동일) -->
<!-- 어디에 기록할 것인가 (콘솔Appender) -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <!-- 콘솔에 로그를 기록하는 Appender 설정 -->
<encoder> <!-- 어떻게 출력할 것인가 Encoder -->
<pattern>${CONSOLE_LOG_PATTERN}</pattern> <!-- 인코딩할 패턴설정 -->
</encoder>
</appender>
</included>
file-info-appender.xml (파일 INFO 저장 로그 설정)
<included> <!-- 어떤 appender를 사용할지 추가 (자바에서 import와 동일) -->
<!-- 롤링 파일Appender: INFO 레벨 이상의 로그를 파일에 기록 -->
<appender name="FILE-INFO" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 파일에 로그를 기록하는 Appender 설정 -->
<!-- 어떻게 출력할 것인가 Encoder -->
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern> <!-- 인코딩할 패턴설정 -->
</encoder>
<!-- 롤링 정책: 로그 파일을 일정 크기 또는 시간 단위로 롤링(분할) -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>./log/pium-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- 롤링된 파일 이름 패턴 설정 -->
<maxFileSize>50MB</maxFileSize> <!-- 최대 파일 크기 설정 -->
<maxHistory>30</maxHistory> <!-- 보관할 최대 파일 수 설정 -->
<totalSizeCap>1GB</totalSizeCap> <!-- 전체 로그 파일의 최대 크기 설정 -->
</rollingPolicy>
</appender>
</included>
file-error-appender.xml (파일 ERROR 저장 로그 설정)
<included> <!-- 어떤 appender를 사용할지 추가 (자바에서 import와 동일) -->
<!-- 에러 로그를 기록할 롤링 파일Appender: ERROR 레벨 로그만 기록 -->
<appender name="FILE-ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 로깅 필터설정 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level> <!-- 필터링할 로그 레벨 설정 -->
<onMatch>ACCEPT</onMatch> <!-- 조건이 맞을 때 로그 기록 허용 -->
<onMismatch>DENY</onMismatch> <!-- 조건이 맞지 않을 때 로그 기록 거부 -->
</filter>
<!-- 어떻게 출력할 것인가 Encoder -->
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern> <!-- 파일에 기록할 패턴 설정 -->
</encoder>
<!-- 롤링 정책: 로그 파일을 일정 크기 또는 시간 단위로 롤링(분할) -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>./log/pium-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- 롤링된 파일 이름 패턴 설정 -->
<maxFileSize>50MB</maxFileSize> <!-- 최대 파일 크기 설정 -->
<maxHistory>30</maxHistory> <!-- 보관할 최대 파일 수 설정 -->
<totalSizeCap>3GB</totalSizeCap> <!-- 전체 로그 파일의 최대 크기 설정 -->
</rollingPolicy>
</appender>
</included>
환경별로 로그 전략을 분리 (로컬환경, develop환경, blue환경, green환경)
<?xml version="1.0" encoding="UTF-8"?>
<!-- 어떻게 기록할 것인가 (Logger)--> <!-- 로깅 설정 파일 (logback-spring.xml) -->
<configuration>
<!-- 로그 컬러 설정 컨버터 -->
<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"/>
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %5level %logger - %msg%n"/>
<!--local 환경에서의 로그설정-->
<springProfile name="local">
<!-- include = 어떤 appender를 사용할지 추가 (자바 import와 동일) -->
<include resource="console-appender.xml"/>
<!-- 루트 로거 설정: INFO 레벨 이상의 로그를 콘솔에 기록 -->
<root level="INFO">
<appender-ref ref="CONSOLE"/> <!-- 필요한 appender 이름을 appender-ref 태그에 추가 -->
</root>
</springProfile>
<!--develop 환경에서의 로그설정-->
<springProfile name="develop">
<!-- include = 어떤 appender를 사용할지 추가 (자바 import와 동일) -->
<include resource="file-error-appender.xml"/>
<!-- 루트 로거 설정: ERROR 레벨의 로그를 파일에 기록 -->
<root level="ERROR">
<appender-ref ref="FILE-ERROR"/> <!-- 필요한 appender 이름을 appender-ref 태그에 추가 -->
</root>
</springProfile>
<!--blue 환경에서의 로그설정-->
<springProfile name="blue">
<!-- include = 어떤 appender를 사용할지 추가 (자바 import와 동일) -->
<include resource="file-error-appender.xml"/>
<!-- 루트 로거 설정: ERROR 레벨의 로그를 파일에 기록 -->
<root level="ERROR">
<appender-ref ref="FILE-ERROR"/> <!-- 필요한 appender 이름을 appender-ref 태그에 추가 -->
</root>
</springProfile>
<!--green 환경에서의 로그설정-->
<springProfile name="green">
<!-- include = 어떤 appender를 사용할지 추가 (자바 import와 동일) -->
<include resource="file-error-appender.xml"/>
<!-- 루트 로거 설정: ERROR 레벨의 로그를 파일에 기록 -->
<root level="ERROR">
<appender-ref ref="FILE-ERROR"/> <!-- 필요한 appender 이름을 appender-ref 태그에 추가 -->
</root>
</springProfile>
</configuration>