Spring은 logback.xml
Spring Boot는 logback-spring.xml
build.gradle
configurations.all {
exclude group: 'commons-logging', module: 'commons-logging'
}
dependencies {
compile group: 'org.slf4j', name: 'slf4j-api', version: '2.0.0-alpha1'
compile group: 'org.slf4j', name: 'jcl-over-slf4j', version: '2.0.0-alpha1'
compile group: 'ch.qos.logback', name: 'logback-classic', version: '1.3.0-alpha5'
}
logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="LOG_PATH" value="logs" />
<property name="LOG_FILE_NAME" value="log" />
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${LOG_FILE_NAME}.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd} | %d{HH:mm:ss.SSS} | %-20.20thread | %-5level | %-25.25logger{25} | %-4line | %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/archive/${LOG_FILE_NAME}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>7</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd} | %d{HH:mm:ss.SSS} | %-20.20thread | %-5level | %-25.25logger{25} | %-4line | %msg%n</pattern>
</layout>
</appender>
<logger name="jdbc.sqltiming" level="WARN" additivity="false" />
<logger name="jdbc.audit" level="OFF" />
<logger name="jdbc.resultset" level="OFF" />
<logger name="jdbc.resultsettable" level="OFF" />
<logger name="jdbc.sqlonly" level="OFF" />
<logger name="jdbc.connection" level="OFF" />
<root level="WARN">
<appender-ref ref="FILE" />
<appender-ref ref="STDOUT" />
</root>
</configuration>
로그 필터링
implementation 'org.codehaus.janino:janino:3.1.8'
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator>
<expression>message.contains("NOT_SQL_LOG")</expression>
</evaluator>
<onMismatch>NEUTRAL</onMismatch>
<onMatch>DENY</onMatch>
</filter>
<encoder>
<pattern>%d{yyyy-MM-dd} | %d{HH:mm:ss.SSS} | %-20.20thread | %-5level | %-25.25logger{25} | %-4line | %msg%n</pattern>
</encoder>
</appender>
-- NOT_SQL_LOG
SELECT *
FROM USERS
onMismatch, onMatch
ACCEPT | 허용 |
DENY | 거부 |
NEUTRAL | 중립 |
필터가 여러개인 경우 ACCEPT와 DENY의 경우 바로 값이 리턴되어서 적용 됨.
순서대로 모든 필터를 검증하려면 NEUTRAL 값 사용.
로그 레벨 필터링
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
<file>logs/error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/archive/error-%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10mb</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd} | %d{HH:mm:ss.SSS} | %-20.20thread | %-5level | %-25.25logger{25} | %-4line | %msg%n</pattern>
</encoder>
</appender>
pattern 유형
패턴의미
%d | 시간(yyyy-MM-dd HH:mm:ss, SSS형태) |
%date{format} | 원하는 형태로 시간 정보 출력 예) %date{yyyy.MM.dd HH:mm:ss.SSS} |
%logger{length} | Logger이름. {length}는 최대 자리수. |
%thread | 현재 스레드 이름 |
%-5level | 로그 레벨 5는 출력 고정폭 값 |
%line | 로그 라인 |
%msg | 로그 메시지 |
%n | 개행(new line) 처리 |
<!-- [2022.10.12 14:29:49] [Executor-10] [c.d.d.m.MigrationService :97] INFO 2011-10 MigrationService 0/100 -->
<pattern>%d{[yyyy.MM.dd HH:mm:ss]} [%-35.35c{1}:%line] %-5p %msg%n</pattern>
<!-- 2022-10-12 | 14:38:37.310 | Executor-20 | INFO | c.d.d.m.MigrationService | 2022-05 MigrationService.run() 종료 1s -->
<pattern>%d{yyyy-MM-dd} | %d{HH:mm:ss.SSS} | %-20.20thread | %-5level | %-25.25logger{25} | %-4line | %msg%n</pattern>
로그 필터링 응용(Long Query 조회)
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
<appender name="SQL-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/sql/sql.log</file>
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
<evaluator>
<matcher>
<name>matcher</name>
<regex>executed in [0-9]{4,}</regex>
</matcher>
<expression>matcher.matches(formattedMessage)</expression>
</evaluator>
<onMismatch>DENY</onMismatch>
<onMatch>ACCEPT</onMatch>
</filter>
<encoder>
<pattern>%d{yyyy-MM-dd} | %d{HH:mm:ss.SSS} | %-20.20thread | %-5level | %-25.25logger{25} | %-4line | %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>sql/sql.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>50MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>7</maxHistory>
<totalSizeCap>1GB</totalSizeCap>
</rollingPolicy>
</appender>
<appender name="SQL-FILE-ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="SQL-FILE" />
<queueSize>4096</queueSize>
<discardingThreshold>0</discardingThreshold>
<includeCallerData>true</includeCallerData>
<neverBlock>false</neverBlock>
</appender>
<logger name="jdbc.sqltiming" level="INFO" additivity="false">
<appender-ref ref="SQL-FILE-ASYNC" />
</logger>
<logger name="jdbc.audit" level="OFF" />
<logger name="jdbc.resultset" level="OFF" />
<logger name="jdbc.resultsettable" level="OFF" />
<logger name="jdbc.sqlonly" level="OFF" />
<logger name="jdbc.connection" level="OFF" />
<root level="INFO">
</root>
</configuration>
비동기 로그
별도의 Thread를 생성하여 로그를 출력하는 방법.
※로그 손실 가능성 있음.
<configuration scan="true" scanPeriod="30 seconds">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd} | %d{HH:mm:ss.SSS} | %-20.20thread | %-5level | %-25.25logger{25} | %-4line | %msg%n</pattern>
</layout>
</appender>
<appender name="STDOUT-ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="STDOUT" />
<!-- queue의 사이즈 -->
<queueSize>4096</queueSize>
<!-- queue의 용량이 일정비율 이상 채워졌을 때 해당 비율 만큼 trace, debug, info level의 event를 삭제 함 -->
<!-- 기본 20(20%), 0으로 할 경우 삭제하지 않음 -->
<discardingThreshold>20</discardingThreshold>
<!-- 로그를 호출한 라인수 정보 취득(성능에 영향 있음.) -->
<includeCallerData>false</includeCallerData>
<!-- queue에 용량이 가득찰 경우 blocking 상태에 빠지게 되는데, true로 하게 되면 log를 삭제하면서 계속 진행함. -->
<neverBlock>true</neverBlock>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT-ASYNC" />
</root>
</configuration>
FileAppender
가동할 때 마다 파일로그를 갱신하고 싶을 경우
RollingFileAppender는 append 옵션이 true로 고정되어 있으므로
FileAppender를 이용해야 함.
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<!-- true로 할 경우 항상 새로운 파일이 생성 됨. -->
<append>false</append>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
<file>logs/error/error.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd} | %d{HH:mm:ss.SSS} | %-20.20thread | %-5level | %-25.25logger{25} | %-4line | %msg%n</pattern>
</encoder>
</appender>
반응형
'Java > Java' 카테고리의 다른 글
Spring @Async 어노테이션 사용 (0) | 2023.07.16 |
---|---|
Java Optional 사용법 (0) | 2023.07.16 |
Java FX + Eclipse 개발 세팅 (0) | 2023.07.16 |
Java에서 EzTransXP(일본어번역기) 사용법 (0) | 2021.06.07 |
AES256 암복호화 (0) | 2021.06.07 |
댓글