이제 두번째 기술 포스팅이다.
사실 실제 개발을 진행하는 것조차 힘에 부치기 때문에... 기술 블로그까지 내가 운영할 수 있을까? 라는 생각이 들기도 하고, 다른 좋은 블로그들 많은데 내가 이런거 정리 해두는게 의미도 크게 없을 것 같다는 생각을 했는데
결정적으로 이번 게시글은 반드시 정리해야겠다고 생각하게 만든 계기가 있다.
어떻게 하나같이 Configutation 이라는 오타를 똑같이 낼 수가 있는 것일까?
예시를 4개만 들고 왔는데 구글 검색 결과의 상위 6개인가가 다 똑같아서 이놈의 기술 블로그들을 도저히 신뢰할 수가 없다는 판단이 섰다.
(이 웃긴 사람들의 블로그 다른 게시물들을 보면 아주 진지하고 스마트한 개발자임을 뽐내고 있다는 것이 조금 애잔했다.)
원래 이 기술블로그라는 것의 생태가 이렇게 얄팍하고 어이없는 것인지 몰랐는데,
이렇게 황당하기 짝이 없는 행태를 목도하고 나니 '내가 직접 작성해야 쓰것다' 라는 생각이 절로 들었다.
사담은 집어 치우고...
log4j2 설정 아웃라인을 간단하게 요약, 정리해놓으려고 한다.
세부적인건 당연히 공식문서를 봐야겠고 또 지금 내 수준에서는 세부적인 설정도 필요하지 않을 것 같음
고수분께 log4j2 configuration 어떻게 하냐고 질문한 결과를 먼저 보고,
설정 파일이 대충 어떤 형태인지를 파악하고,
각각의 설정 컴포넌트를 정리해놓은 글을 보면
이해가 빨리 될 것이다.
log4j의 설정 파일은 json, xml, properties, yaml 등 전부 지원이 된다고 하는데 밑의 예시는 xml이다.
xml이 json, yaml로 정확히 1:1 매칭이 되도록 변환이 되는지는 아직 모르겠다.
▶ 콘솔 로그 설정
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace">
<Appenders>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{35} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="INFO" additivity="false">
<AppenderRef ref="console"/>
</Root>
</Loggers>
</Configuration>
▶ 파일 로그 설정
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info">
<Appenders>
<Routing name="RoutingAppender">
<Routes pattern="$${level}">
<Route key="INFO">
<RollingFile name="RollingFile-Info" fileName="/var/log/imhere-server/info/info-${date:yyyy-MM-dd}.log"
filePattern="./backup/info/info-%d{yyyy-MM-dd}-%i.log">
<LevelRangeFilter minLevel="INFO" maxLevel="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<Policies>
<SizeBasedTriggeringPolicy size="10MB" />
<TimeBasedTriggeringPolicy />
</Policies>
<DefaultRolloverStrategy>
<Delete basePath="./logs/info" maxDepth="1">
<IfLastModified age="60d" />
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
</Route>
<Route key="WARN">
<RollingFile name="RollingFile-Warn" fileName="/var/log/imhere-server/warn/warn-${date:yyyy-MM-dd}.log"
filePattern="./backup/warn/warn-%d{yyyy-MM-dd}-%i.log">
<LevelRangeFilter minLevel="WARN" maxLevel="WARN" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<Policies>
<SizeBasedTriggeringPolicy size="10MB" />
<TimeBasedTriggeringPolicy />
</Policies>
<DefaultRolloverStrategy>
<Delete basePath="./logs/warn" maxDepth="1">
<IfLastModified age="60d" />
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
</Route>
<Route key="ERROR">
<RollingFile name="RollingFile-Error" fileName="/var/log/imhere-server/error/error-${date:yyyy-MM-dd}.log"
filePattern="./backup/error/error-%d{yyyy-MM-dd}-%i.log">
<LevelRangeFilter minLevel="ERROR" maxLevel="OFF" onMatch="ACCEPT" onMismatch="DENY"/>
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<Policies>
<SizeBasedTriggeringPolicy size="10MB" />
<TimeBasedTriggeringPolicy />
</Policies>
<DefaultRolloverStrategy>
<Delete basePath="./logs/error" maxDepth="1">
<IfLastModified age="60d" />
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
</Route>
</Routes>
</Routing>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="RoutingAppender"/>
</Root>
</Loggers>
</Configuration>
하나 하나 설정 컴포넌트를 짚어보면
1. Configuration | root element로 모든 컴포넌트를 담고있다. 참고로 Configutation 으로 오타를 내도 동작한다. 사실 그 자체로 별 의미는 없으니까... |
2. Appenders | 자바의 리스트 같은 자료구조에 append 메서드가 자료를 추가하는 메서드이듯이 얘는 log를 console 또는 file 형태로 추가해주는 놈이라고 보면 된다. 다시말해 어디에 로그를 찍어줄 지를 결정한다. ex) console, file, database ... |
3. Logger | logger = log를 찍는 사람 어떤 로그를 찍을 지 결정하는 변수다. 어느정도의 수위로 로그를 찍을 건지 정하면 된다. 심각한 순서대로 하면 ex) OFF, FATAL, ERROR, WARN, INFO, DEBUG, and TRACE |
4. PatternLayout | 제곧내 pattern은 밋밋 version : %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n pretty version : %d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} %highlight{${LOG_LEVEL_PATTERN:-%5p}}{FATAL=red blink, ERROR=red, WARN=yellow bold, INFO=green, DEBUG=green bold, TRACE=blue} %style{${sys:PID}}{magenta} [%15.15t] %style{%-40.40C{1.}}{cyan} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx} 으로 설정하면 된다. 자세한 내용은 아래 공식 문서 참조 https://logging.apache.org/log4j/2.x/manual/layouts.html |
5. Routing | 로그를 라우팅해주는 컴포넌트 공식 문서에는 Arbiter에 포함 되는 개념인데 로그를 분류해서 어떻게 처리할 지를 정해주는 컴포넌트이다 그래서 하위 컴포넌트들을 보면 어떻게 분류해서 어떻게 처리할지를 보여준다. |
개략적으로 큰 요소들만 짚어봤는데, 로그라는 것이 개발 및 유지보수에서 매우 중요하기 때문에
세부적으로 로그를 설정하는 방법들이 아주 아주 다양하다. 이걸 전부 여기에 정리하는 건 오바고...
이거 보다 자세한 내용은 아래 공식 문서 참조...!!
https://logging.apache.org/log4j/2.x/manual/configuration.html#Filters
------------------------------------------ 이후 궁금해서 알아 본 내용 ------------------------------------------
1. Configuration 의 status 와 Logger의 level 의 차이
Loggers 태그를 잘 보면 Logger 뒤에 s가 붙어있다. Logger 가 하나가 아니라는 뜻이다.
각각의 Logger는 서로 다른 역할을 수행하고, 각각의 설정에 의해 동작한다.
Configuration 뒤에 붙은 status는 Status Logger 라는 log4j2의 내부 상태에 대한 log를 찍어주는 Logger로,
단적으로 이야기해서 내가 개발하고 있는 프로젝트랑은 관련이 없다고 봐도 무방하다.
log4j2의 새로 configuration을 작성하거나, 수정할 때나 필요할 것이다.
반면 Loggers 하위의 Root 태그의 level attribute는 현재 실행되는 프로젝트에 대한 로깅 수준을 설정하므로
내가 구체적으로 어떤 수준의 이벤트에 관심이 있는지를 설정해 주면 된다.
Reference :
https://stackoverflow.com/questions/67265906/log4j-difference-between-configuration-and-level
2. Ievet의 level 종류
Log level은 아래와 같이 총 7개로 이루어져있다.
Level | Description |
ALL | All levels including custom levels. |
DEBUG | Designates fine-grained informational events that are most useful to debug an application. |
INFO | Designates informational messages that highlight the progress of the application at coarse-grained level. |
WARN | Designates potentially harmful situations. |
ERROR | Designates error events that might still allow the application to continue running. |
FATAL | Designates very severe error events that will presumably lead the application to abort. |
OFF | The highest possible rank and is intended to turn off logging. |
TRACE | Designates finer-grained informational events than the DEBUG. |
Reference :
https://www.tutorialspoint.com/log4j/log4j_logging_levels.htm