배포 환경에서, 그리고 개발하면서 api를 맞춰보면서 특정 문제가 발생했을 때 그에 대한 기록을 남겨두면 이후에 그 기록을 바탕으로 대처를 할 수 있다. Spring에서는 다양한 logging configurations들을 제공한다. log4j, logback, log4j2들이 대표적이다.
이번 포스팅에선 log4j2를 선택한 이유와, 개발 및 배포환경에서 각각 다른 log4j2 yml을 어떻게 만들었는지 작성해보도록 하겠다.
logback vs log4j2
log4j는 2015년에 서비스가 종료됐고, 오래된 로그 프레임워크이기 때문에 제외하도록 하겠다.
logback
- log4j 개발팀이 제작하여 기본적으로 log4j와 비슷하지만 성능이 향상됨.
- spring-boot-starter-web의 기본 로깅 프레임워크
log4j2
- logback, log4j의 단점을 개선한 로깅 프레임워크
- logback보다 탁월한 성능 및 다양한 appender 제공
이러한 이유로 log4j2가 성능이 가장 좋다는 점, logback의 단점을 개선한 로깅 프레임워크라는 점을 고려하여 log4j2를 활용하기로 했다. 혹시 log4j2를 사용하지 않고 logback을 사용한 이유가 존재한다면 댓글 부탁!
환경세팅
build.gradle
configurations { /*logback 의존성 제거*/
all {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
}
}
dependencies { /*log4j2 의존성 추가*/
implementation 'org.springframework.boot:spring-boot-starter-log4j2'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml'
}
spring-boot-starter-web에서 기본으로 제공하는 logback 로깅 프레임워크 의존성을 제거하지 않으면 에러가 발생한다.
application.yml
logging:
config: classpath:log4j2.yml
만약 로컬환경과 개발환경, 배포환경이 나누어져있다면 logging의 config를 그에 맞게 수정해주면 된다.
우리의 경우는 아래와 같이 하였다.
# application.yml
logging:
config: classpath:log4j2.yml
# application-develop.yml
logging:
config: classpath:log4j2-develop.yml
# application-deploy.yml
logging:
config: classpath:log4j2-deploy.yml
로깅 전략
로깅 전략에 따라서 log4j2 yml 파일의 내용이 달라진다.
우리는 로컬에서는 file(단일 파일, 재실행 시 사라짐), rollingfile(아카이브화 하여 보관)로 남길 필요가 없다고 판단하여 Appender를 Console로 설정했다.
개발 환경에서는 배포하기 전 API를 맞춰봐야 하기 때문에 File로 남겨두는 것이 좋다고 판단해 File_Appender로 설정했다.
배포 환경에서는 로그 파일을 보관하는 것이 좋다고 판단해 RollingFile_Appender로 설정했다.
로컬과 개발 환경에서는 DEBUG, 배포 환경에서는 INFO로 로그 레벨을 설정했다.
그러나, 로컬과 개발에서 Spring Application을 구동 시 스프링 관련 불필요한 정보들이 너무 많이 출력돼 Root log level은 INFO로, Controller 패키지 이하에서는 DEBUG로 설정하는 방식으로 변경했다.
log4j2.yml (로컬 환경)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
Configutation:
name: Default
status: info
Properties:
Property:
name: log-path
value: "logs"
Appenders:
Console:
name: Console_Appender
target: SYSTEM_OUT
PatternLayout:
pattern: "%style{%d{yyyy-MM-dd HH:mm:ss.SSS}}{cyan} %highlight{[%-5p]}{FATAL=bg_red,
ERROR=red, INFO=green, DEBUG=blue, TRACE=bg_yellow} [%C] %style{[%t]}{yellow}- %m%n"
Loggers:
Root:
level: info
AppenderRef:
- ref: Console_Appender
Logger:
- name: com.woowacourse.naepyeon
additivity: false
level: debug
AppenderRef:
- ref: Console_Appender
|
cs |
log4j2-develop.yml (개발 환경)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
Configutation:
name: Default
status: info
Properties:
Property:
name: log-path
value: "logs"
Appenders:
File:
name: File_Appender
fileName: ${log-path}/logfile.log
append: false
PatternLayout:
pattern: "%style{%d{yyyy-MM-dd HH:mm:ss.SSS}}{cyan} %highlight{[%-5p]}{FATAL=bg_red,
ERROR=red, INFO=green, DEBUG=blue, TRACE=bg_yellow} [%C] %style{[%t]}{yellow}- %m%n"
Loggers:
Root:
level: info
AppenderRef:
- ref: File_Appender
Logger:
- name: com.woowacourse.naepyeon
additivity: false
level: debug
AppenderRef:
- ref: File_Appender
|
cs |
log4j2-deploy.yml (배포 환경)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
Configutation:
name: Default
status: info
Properties:
Property:
name: log-path
value: "logs"
Appenders:
RollingFile:
- name: RollingFile_Appender
fileName: ${log-path}/rollingfile.log
filePattern: "${log-path}/archive/rollingfile.log_%d{yyyy-MM-dd}-%i.gz"
PatternLayout:
pattern: "%style{%d{yyyy-MM-dd HH:mm:ss.SSS}}{cyan} %highlight{[%-5p]}{FATAL=bg_red,
ERROR=red, INFO=green, DEBUG=blue, TRACE=bg_yellow} [%C] %style{[%t]}{yellow}- %m%n"
Policies:
TimeBasedTriggeringPolicy:
Interval: 1
modulate: true
SizeBasedTriggeringPolicy:
size: "10 MB"
DefaultRollOverStrategy:
max: 10
Delete:
basePath: "${log-path}/archive"
maxDepth: "1"
IfLastModified:
age: "P14D"
IfAccumulatedFileCount:
exceeds: 140
Loggers:
Root:
level: info
AppenderRef:
- ref: RollingFile_Appender
Logger:
- name: com.woowacourse.naepyeon
additivity: false
level: info
AppenderRef:
- ref: RollingFile_Appender
|
cs |
하나하나 찬찬히 살펴보자.
Configuration
Configutation:
name: Default
status: info
로그 설정의 최상위 요소이다. 해당 파일의 루트 로깅 전략의 name과 status를 적어주면 된다.
status는 log level을 적어주면 된다. error, warn, info, debug, trace 중에서 선택하자.
로그 레벨에 대해 좀 더 알아보자. 로그 레벨은 아래 순서를 따른다.
TRACE > DEBUG > INFO > WARN > ERROR
보통은 개발 환경에서는 debug 또는 info, 배포 환경에서는 info를 많이 하는 것으로 보인다.
무조건 많은 정보를 띄운다고 좋은 것이 아니다. 그만큼 용량을 많이 차지하고 불필요한 로그가 기록돼 가독성이 떨어지게 되기 때문이다.
한 번 비교해보자.
아래는 테스트용으로 소나큐브 인프라 세팅 관련 로그를 각각 DEBUG, INFO, WARN으로 설정하여 비교해본 사진이다.
WARN은 30줄임에 비해, INFO는 무려 40,000줄, DEBUG는 45,000줄이다!
이렇게 용량차이가 어마어마하게 난다는 것에 주의해야 한다.
Properties
Properties:
Property:
name: log-path
value: "logs"
해당 Logger의 property를 명시하는 곳이다. key-value값으로 명시해주면 된다.
Appenders
Appenders:
Console:
name: Console_Appender
target: SYSTEM_OUT
PatternLayout:
pattern: "%style{%d{yyyy-MM-dd HH:mm:ss.SSS}}{cyan} %highlight{[%-5p]}{FATAL=bg_red,
ERROR=red, INFO=green, DEBUG=blue, TRACE=bg_yellow} [%C] %style{[%t]}{yellow}- %m%n"
로깅 전략을 명시해주는 부분이다.
- target: 표준 입출력임을 명시
- pattern: 로그 스타일 지정. 가독성이 높아짐. ERROR는 빨간색, INFO는 초록색 등으로 칠해줌
RollingFile_Appender로 할 경우 파일을 저장할 기간, 용량 관리 등을 설정해주어야 하므로 꽤 복잡해진다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
Appenders:
RollingFile:
- name: RollingFile_Appender
fileName: ${log-path}/rollingfile.log
filePattern: "${log-path}/archive/rollingfile.log_%d{yyyy-MM-dd}-%i.gz"
PatternLayout:
pattern: "%style{%d{yyyy-MM-dd HH:mm:ss.SSS}}{cyan} %highlight{[%-5p]}{FATAL=bg_red,
ERROR=red, INFO=green, DEBUG=blue, TRACE=bg_yellow} [%C] %style{[%t]}{yellow}- %m%n"
Policies:
TimeBasedTriggeringPolicy:
Interval: 1
modulate: true
SizeBasedTriggeringPolicy:
size: "10 MB"
DefaultRollOverStrategy:
max: 10
Delete:
basePath: "${log-path}/archive"
maxDepth: "1"
IfLastModified:
age: "P14D"
IfAccumulatedFileCount:
exceeds: 140
|
cs |
- File
- name : RollingFileAppender 이름
- fileName : 저장할 파일 경로, 이름에 날짜 형식을 지정하여 저장 가능 (Properties에 지정한 logs 디렉토리의 archive 디렉토리 아래에 rollingfile.log_%d{yyyy-MM-dd}.gz 파일명으로 로그 저장)
- PatternLayout : 로그 출력 양식 지정
- Policy : File RollingUp의 기준을 지정
- OnStartupTriggeringPolicy : jvm start시 trigger
- TimeBasedTriggeringPolicy + Interval : time에 따른 trigger(파일 이름 패턴의 최소단위 날짜로 계산, 위 예시는 하루에 한 번 RollingUp). 위 예시는 하루 단위로 압축 보관하도록 함.
- SizeBasedTriggeringPolicy + size : file size에 따른 trigger.
- CronTriggeringPolicy : Cron Expression(시간에 관한 표현)에 따른 trigger
- DefaultRollOverStrategy : Rolling File을 Over(삭제)하는 기준을 지정
- max: 동시간대에 최대 10개까지 RollingFiles가 생성될 수 있도록 지정
- basePath: 아카이브화할 로그 파일 위치 지정. (Properties에 지정한 logs 디렉토리의 archive 디렉토리 아래에 rollingfile.log_%d{yyyy-MM-dd}.gz 파일명으로 로그 저장)
- IfLastModified - age: "P14D": 수정된지 14일이 지난 파일은 삭제
- IfAccumulatedFileCount : RollingUp된 압축파일을 저장하는 디렉토리에 존재할 수 있는 파일 개수. 파일 개수를 넘으면 오래된 파일부터 삭제(총 140개 초과시 오래된 파일부터 삭제)
자세한 내용은 공식 문서를 참고하자.
https://logging.apache.org/log4j/2.x/manual/appenders.html#RollingFileAppender
위와 같이 아카이브화 된 로그파일들이 남는 것을 확인할 수 있다.
Loggers
Loggers:
Root:
level: info
AppenderRef:
- ref: Console_Appender
Logger:
- name: com.woowacourse.naepyeon
additivity: false
level: debug
AppenderRef:
- ref: Console_Appender
로깅을 직접하는 요소, 로거는 패키지 별도로 설정이 가능하다. Root 패키지의 로거는 필수적으로 세팅해주어야 하며, 추가적인 로거를 설정하려면 Logger로 설정해주어야 한다.
- level : 해당 패키지에 찍을 최하 로그 레벨을 지정
- additivity : false로 지정시 로그가 중복으로 찍히는 것을 방지 (기본값: true)
- AppenderRef : ref속성으로 적용할 Appender를 지정
여력이 된다면 위 로깅전략을 활용한 로그 인터셉터 구현 관련 포스팅도 작성해보도록 하겠다.
참고
- log4j2 공식문서: https://logging.apache.org/log4j/2.x/index.html
- 로깅 프레임워크 비교글 1: https://programmer.group/java-logging-framework-log4j-vs-logback-vs-log4j2.html
- 로깅 프레임워크 비교글 2 (Jinhong님 블로그): https://xlffm3.github.io/spring%20&%20spring%20boot/async-logger-performance/
- Spring 공식문서 로깅 관련: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#features.logging
- 우아한테크코스 내편 프로젝트 로깅 PR: https://github.com/woowacourse-teams/2022-nae-pyeon/pull/353
'JAVA > JAVA | Spring 학습기록' 카테고리의 다른 글
[Spring] @SpringBootTest의 webEnvironment와 @Transactional (5) | 2022.08.23 |
---|---|
[Spring] @MockBean VS @SpyBean (1) | 2022.08.22 |
[JAVA] IoC, DI, DIP (0) | 2022.08.09 |
[Spring] 인증 토큰을 생성하는 JwtTokenProvider를 알아보고 테스트를 작성해보자 (0) | 2022.07.22 |
[Spring] 테스트에서 test 스키마가 아닌 main의 스키마를 의존한다면? _ application.yml 설정 (2) | 2022.06.09 |