- Apache Software Foundation에서 개발한 Java 기반의 로깅 유틸리티이며 Log4J의 업그레이드 버전입니다.
- Log4j에 비해 로깅 기능을 더욱 향상시킨 것으로 향상된 멀티스레드 환경에서의 성능, 로그 메시지의 더 나은 파라미터화, 로그 이벤트에 대한 더 많은 메타데이터 제공 등을 통해 로깅의 유연성과 확장성을 증가시켰습니다.
- Log4j2는 Java 7이상에서만 동작하며 Log4J 1.x, SLF4J, Commons Logging 및 java.util.logging과의 호환성을 유지하면서도 더욱 향상된 로깅 기능을 제공합니다.
[ 더 알아보기 ] 💡 로깅(Logging)이란
- 소프트웨어 개발 및 유지보수 과정에서 중요한 역할을 하는데, 이는 오류 디버깅, 시스템 동작 확인, 보안 이슈 추적 등 다양한 목적으로 사용됩니다.
💡 Log4j와 Log4j2의 차이점은 무엇일까?
- Log4j에 비해 Log4j2는 멀티스레드 환경에서의 성능 향상, 로깅 구성 변경 시 애플리케이션 재시작 없이 동적 로딩, API 개선 등을 제공합니다.
2) Log4j2 주요 특징
1. 비동기 로거 지원
💡 비동기 로거 지원
- Log4j2 로깅 프레임워크의 비동기 로깅 기능을 제공합니다. 이를 사용하면 로그 이벤트를 즉시 처리하지 않고 백그라운드에서 처리하여 응용 프로그램의 성능을 향상합니다.
- 또한 로깅 작업이 애플리케이션의 성능에 미치는 영향을 최소화할 수 있습니다. 또한 다양한 애플리케이션에서 확장성과 성능을 향상하는 데 도움이 됩니다. - 단, 메인 애플리케이션 스레드와 별도의 스레드에서 처리되므로 로그 이벤트가 실제로 로그 파일에 기록되기까지 시간이 걸릴 수 있습니다. 또한, 로그 이벤트 버퍼링과 관련된 설정을 적절히 조정해야 합니다.
💡 [참고] 비동기 로깅 - 최대 처리량 비교
- 해당 그래프에서는 동기 로거, 비동기 어펜더, 비동기 로거의 처리량을 비교합니다. 이는 모든 스레드 별 총처리량입니다. - 64개 스레드를 사용한 테스트에서 비동기 로거는 비동기 어펜더보다 12배 빠르고 동기 로거보다 68배 빠릅니다. - 비동기 로거의 처리량은 스레드 수에 따라 증가하는 반면, 동기 로거와 비동기 어펜더는 모두 로깅을 수행하는 스레드 수에 관계없이 다소 일정한 처리량을 갖습니다.
- Log4j2 설정에 사용하는 구성 요소에 대해 상세히 알아봅니다. - 해당 글은 Log4j2를 yaml 형태로 구성하는 방법을 기준으로 작성하였습니다.
Log4j2 구성요소 요약
💡 요약
- 모든 요소를 다룰 수 없기에 자주 사용되는 요소들에 대해서만 확인해 봅니다.
1차 분류
2차 분류
3차 분류
설명
Configutation
로그 설정의 최상위 항목
Configutation
Properties
로그 설정의 속성을 정의하는 항목
Configutation
Properties
Property
개별 속성을 정의하는 항목
Configutation
Appenders
어플리케이션에서 사용할 로그 출력 방법을 정의하는 항목
Configutation
Appenders
Console
콘솔에 로그를 출력하는 방법을 정의하는 항목
Configutation
Appenders
File
파일에 로그를 출력하는 방법을 정의하는 항목
Configutation
Appenders
RollingFile
파일을 롤링하는 방식으로 로그를 출력하는 방법을 정의하는 항목
Configutation
Loggers
로거를 설정하는 항목
Configutation
Loggers
Logger
일반적인 로거를 정의하는 항목
Configutation
Loggers
root
루트 로거를 정의하는 항목
1. Configuration
💡 Configuration - 로깅 구성의 기초를 형성하는 데 사용하며 컴포넌트들이 어떻게 함께 동작을 하는지에 대해 정의하며 ‘로깅 동작의 전반적인 관리’를 담당합니다.
- 로깅 파일을 구성하는 형태로는 XML, JSON, YAML, properties 파일 또는 프로그램 코드로 작성할 수 있습니다.. - 로깅 요청이 어떤 Appender로 라우팅 되어야 하는지 어떤 로그 메시지가 필터링되어야 하는지 등을 결정합니다. 이는 프로그램의 로깅 동작을 세밀하게 제어할 수 있게 해 줍니다
1차 분류
속성
설명
Configutation
name
구성 파일의 이름을 정의합니다.
Configutation
status
구성 파일의 상태(로그레벨)을 지정합니다. 해당 값으로는 "off", "trace", "debug", "info", "warn", "error", "fatal", "all"를 가집니다.
- 아래와 같은 형태로 Configutation > Properties 형태로 구성되어 있으며 하위 속성으로 Property 내에서는 ‘경로’ 혹은 ‘변수’를 지정하기 위해 사용됩니다. - 이를 통해 중앙에서 관리되며 다른 속성에서 해당 값을 ${name} 값으로 호출하여 사용이 가능합니다.
- 콘솔에 로그 메시지를 작성하는 방식을 정의합니다. - 이 요소의 이름은 'console-appender'이고 로그 메시지는 시스템 출력(SYSTEM_OUT)에 기록됩니다. - PatternLayout 요소는 로그 메시지의 형식을 정의하며, 이 경우 'layout-pattern' 속성을 참조하여 형식화합니다.
2. Appenders - File - 로그를 파일에 기록하는 방식을 정의합니다. - 각각의 파일 Appender는 서로 다른 파일(info-log, error-log, auth-log, json-log)에 로그를 기록합니다. - 각 파일 Appender는 로그 메시지의 형식을 정의하는 PatternLayout을 가지고 있습니다.
3. Appenders - RollingFile
- 로그를 파일들을 압축파일로 출력하는 방식을 정의합니다. - 로그 메시지는 'rolling-file-log.log'라는 파일에 기록되며, 파일 크기가 200KB에 도달하거나 매일 1회씩 새 파일로 롤링됩니다. - 롤링 로그 파일은 'log-path' 디렉터리의 'archive' 하위 디렉터리에 저장되며, 저장되는 파일의 이름은 'rollingFile.log.'에 날짜 및 시간 정보가 추가된 형식입니다. - 롤링된 로그 파일은 최대 30개까지 유지되며, 그 이상의 파일은 삭제됩니다.
- 로그 메시지가 어떤 수준에서 기록될 것인지 결정합니다. 이 속성의 값은 특정 수준에 대한 로그 메시지의 처리 방법을 정의하는 Logger 인스턴스입니다. - 예를 들어, DEBUG, INFO, WARN, ERROR 등 다양한 로그 수준을 설정할 수 있습니다. 특정 수준을 설정하면 그 수준과 그 이상의 중요도를 가진 메시지만 기록됩니다.
1차 분류
2차 분류
3차 분류
설명
Configutation
Loggers
로거를 설정하는 항목
Configutation
Loggers
Logger
일반적인 로거를 정의하는 항목
Configutation
Loggers
root
루트 로거를 정의하는 항목
💡 사용예시 - 해당 예시에서는 로거를 통해 메시지가 어떤 수준에서 기록될 것인지를 결정합니다.
1. Loggers > Root
- 모든 로그의 기록하는 최상위 로거를 정의합니다.
- 루트 로거의 레벨로 'OFF'가 설정되어 있으며, 'console-appender'와 'rolling-file-appender'를 참조하고 있습니다.
2. Loggers > Logger - 특정 패키지 또는 클래스에 대한 로그를 정의합니다.
- org.springframework와 com.adjh.multiflexapi 패키지에 대해 'INFO'와 'DEBUG' 레벨의 로그를 각각 정의하고 있으며, 각 로거는 'console-appender', 'file-info-appender', 'file-error-appender'를 참조하고 있습니다. - MyBatis 관련 로그 레벨을 지정합니다. 특정 패키지 외에는 모두 'OFF'로 설정되어 있습니다. 'jdbc.sqltiming' 패키지만 'INFO' 레벨로 설정되어 있습니다.
Configutation:
# [Loggers] 로그 출력 범위를 정의
Loggers:
# [Loggers - Root] 모든 로그를 기록하는 최상위 로그를 정의
Root:
level: OFF
AppenderRef:
- ref: console-appender
- ref: rolling-file-appender
# [Loggers - Loggers] 특정 패키지나 클래스에 대한 로그를 정의
Logger:
# 1. Spring Framework 로그 레벨 'INFO' 정의
- name: org.springframework
additivity: "false"
level: INFO
AppenderRef:
- ref: console-appender
- ref: file-info-appender
- ref: file-error-appender
# 2. Spring Framework 로그 레벨 'DEBUG' 정의
- name: com.adjh.multiflexapi
additivity: "false"
level: DEBUG
AppenderRef:
- ref: console-appender
- ref: file-info-appender
- ref: file-error-appender
# 3. MyBatis 관련 로그 레벨 특정 패키지 외에는 모두 OFF
- name: jdbc
level: OFF
- name: jdbc.sqlonly
level: OFF
- name: jdbc.sqltiming
level: INFO
- name: jdbc.resultsettable
level: OFF
- name: jdbc.audit
level: OFF
- name: jdbc.resultset
level: OFF
- name: jdbc.connection
level: OFF
4) Log4j2 환경구성 설정 방법 : yaml을 이용한 방식
1. 기존 문제 확인
💡 기존 문제 확인
- 기존에는 log4j2 로그 환경설정 파일을 xml 형태로 관리가 되었습니다. - xml은 yml 파일보다 상대적으로 가독성이 떨어진다는 단점을 가지고 기존 xml 파일을 yml 파일로 변경합니다.
💡 [참고] 이전에 xml 형태를 사용한 방법에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
4. properties 파일 내에 로깅 설정을 합니다. : application.properties
# default Logging 프레임워크 설정 파일을 참조
logging.config=classpath:log4j2/log4j2-local.yml
# or
# logging slf4j
logging:
# default Logging 프레임워크 설정 파일을 참조
config: classpath:log4j2/log4j2-local.yml
5. 위에서 지정한 경로에 yml 파일을 생성합니다.
6. 해당 파일들을 구성해 줍니다.: src/resources/log4j2-local.yml
💡 해당 파일들을 구성해 줍니다.
- 이전에 구성한 방식과 비교하여 yml 형태로 구성하였고 기존 Camel Case, Snake Case로 변수가 혼동되는 부분을 Dash Case로 변경하였습니다. - 또한 위에서 설명한 내용을 기반으로 구성하였습니다.
Configutation:
# 구성 이름
name: multiflex-api-local
# [Properties] 설정에 사용되는 속성들을 정의
Properties:
Property:
- name: "log-path"
value: "./logs"
- name: "charset-UTF-8"
value: "UTF-8"
- name: "layout-pattern"
value: "%style{%d}{black} %highlight{%-5level} [%style{%t}{bright,blue}] %style{%C}{bright,yellow}: %msg%n%throwable"
- name: "info-log"
value: ${log-path}/tugboatApi/api-info.log
- name: "error-log"
value: ${log-path}/tugboatApi/api-error.log
- name: "auth-log"
value: ${log-path}/tugboatApi/api-auth.log
- name: "json-log"
value: ${log-path}/tugboatApi/api-json-info.log
# [Appenders] 로그 기록방식 정의
Appenders:
# [Appenders - Console] 콘솔에 로그를 출력하는 방식 정의
Console:
- name: console-appender
target: SYSTEM_OUT
PatternLayout:
pattern: ${layout-pattern}
# [Appenders - RollingFile] 로그를 파일들을 압축파일로 출력하는 방식 정의
RollingFile:
name: rolling-file-appender
fileName: ${log-path}/rolling-file-log.log
filePattern: "${log-path}/archive/rollingFile.log.%d{yyyy-MM-dd-hh-mm}_%i.gz"
PatternLayout:
charset: ${charset-UTF-8}
pattern: ${layout-pattern}
Policies:
SizeBasedTriggeringPolicy:
size: "200KB"
TimeBasedTriggeringPolicy:
interval: "1"
DefaultRollOverStrategy:
max: "30"
fileIndex: "max"
# [Appenders - File] 로그를 파일로 기록하는 방식 정의
File:
- name: file-info-appender
fileName: ${info-log}
PatternLayout:
pattern: "%d %p %C{1.} [%t] %m%n"
- name: file-error-appender
fileName: ${error-log}
PatternLayout:
pattern: "%d %p %C{1.} [%t] %m%n"
- name: file-auth-appender
fileName: ${auth-log}
PatternLayout:
pattern: "%d %p %C{1.} [%t] %m%n"
- name: file-json-info-appender
fileName: ${json-log}
PatternLayout:
pattern: "%d %p %C{1.} [%t] %m%n"
# [Loggers] 로그 출력 범위를 정의
Loggers:
# [Loggers - Root] 모든 로그를 기록하는 최상위 로그를 정의
Root:
level: OFF
AppenderRef:
- ref: console-appender
- ref: rolling-file-appender
# [Loggers - Loggers] 특정 패키지나 클래스에 대한 로그를 정의
Logger:
# 1. Spring Framework 로그 레벨 'INFO' 정의
- name: org.springframework
additivity: "false"
level: INFO
AppenderRef:
- ref: console-appender
- ref: file-info-appender
- ref: file-error-appender
# 2. Spring Framework 로그 레벨 'DEBUG' 정의
- name: com.adjh.multiflexapi
additivity: "false"
level: DEBUG
AppenderRef:
- ref: console-appender
- ref: file-info-appender
- ref: file-error-appender
# 3. MyBatis 관련 로그 레벨 특정 패키지 외에는 모두 OFF
- name: jdbc
level: OFF
- name: jdbc.sqlonly
level: OFF
- name: jdbc.sqltiming
level: INFO
- name: jdbc.resultsettable
level: OFF
- name: jdbc.audit
level: OFF
- name: jdbc.resultset
level: OFF
- name: jdbc.connection
level: OFF
[ 더 알아보기 ] 💡yaml/yml 파일 내에서 Boolean 형을 String으로 작성한 이유는?
- yaml 1.2 버전에서는 기존 1.1에 비해 엄격하게 적용하여 ‘true’ / ‘false’에 대해 유효한 Boolean으로 허용이 된다고 합니다. - 참고 글 : https://support.oneskyapp.com/hc/en-us/articles/222417827-Why-do-my-yes-no-keys-in-my-YML-file-change-to-boolean-true-false-