logback.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <pattern>▶ %-5level %d{HH:mm:ss.SSS} [%thread] %class{36}.%method:%line - %msg%n</pattern> </encoder> </appender> <logger name="org.springframework" level="INFO" /> <root level="info"> <appender-ref ref="console" /> </root> </configuration>
logback.groovy
def HOSTNAME = hostname // scope 룰 때문에 nested block에서는 hostname 변수 사용불가 appender('console', ConsoleAppender) { encoder(PatternLayoutEncoder) { pattern = "▶ %-5level %d{HH:mm:ss.SSS} [${HOSTNAME}] [%thread] %logger{36} - %msg%n" } } root(INFO, ['console'])
appender('daily', RollingFileAppender) { file = "/logs/daily.log" append = true rollingPolicy(TimeBasedRollingPolicy) { fileNamePattern = "/logs/daily.log.%d{yyyy-MM-dd}.gz" // 자동 gz 압축 maxHistory = 10 // 10일간만 보관 } encoder(PatternLayoutEncoder) { pattern = '%-5level %d{yyyy-MM-dd HH:mm:ss} [%thread] %logger{36} - %msg%n' } // 특정 레벨 이상만 로깅 filter(ch.qos.logback.classic.filter.ThresholdFilter) { level = INFO // INFO 이상 레벨만 로깅 } // 마커가 필요할 때 filter(EvaluatorFilter) { evaluator(ch.qos.logback.classic.boolex.OnMarkerEvaluator) { marker = '마커이름' marker = '또다른마커이름' } onMismatch = DENY onMatch = NEUTRAL } }
appender('fixedWindowRollingFile', RollingFileAppender) { file = '/logs/fixedWindowRollingFile.log' append = true encoder(PatternLayoutEncoder) { pattern = '%-5level %d{yyyy-MM-dd HH:mm:ss} [%thread] %logger{36} - %msg%n' } rollingPolicy(ch.qos.logback.core.rolling.FixedWindowRollingPolicy) { fileNamePattern = '/logs/fixedWindowRollingFile.log.%i' minIndex = 1 // xx.log.1 ~ xx.log.5 maxIndex = 5 } triggeringPolicy(ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy) { maxFileSize = '100MB' // 파일 크기 100MB될때마다 롤링 } }
Grep 시에 여러줄로 된 로그를 올바로 grep하기 힘들 경우 multi line 을 single line으로 합쳐서 로깅하면 좀 더 편하게 로깅 가능하다.
CoDeGeneration: Java: Logging in single line for grep
Layout 을 다음과 같이 지정하면 새줄기호(\n)가 \n 문자 그 자체로 표시된다. 예외 Stacktrace까지 모두 한 줄로 합친다.
XML 설정의 경우에는
%replace(%msg){"\n","\\n"} %replace(%xException){"\n", "\\n"}%nopex%n
-- 공백으로 변환됨. %replace(%msg){'[\r\n]', ''}
groovy 설정으로 할 경우에는
%replace(%msg){"\n","\\n"} %replace(%xException){"\\n", "\\\\n"}%nopex%n
LogbackConfigListener
설정시 리스너는 선언 순서에 따라 실행되므로 로깅 관련 리스너를 최상단으로 올려서 로깅 정책이 처음 부터 적용될 수 있도록 처리할 것.A.add(B)
는 A extends B
와 유사하다. 즉, A는 B를 상속하므로, B를 처리하는 어펜더는 A도 함께 처리할 수 있다.ch.qos.logback.ext.spring.web.LogbackConfigListener
혹은 LogbackConfigServlet
사용시 서블릿 컨텍스트 종료시 자동 종료되도록 등록 되는 듯 보임.// assume SLF4J is bound to logback-classic in the current environment LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); loggerContext.stop();
<configuration debug="true"> <!-- in the absence of the class attribute, assume ch.qos.logback.core.hook.DelayingShutdownHook --> <shutdownHook/> .... </configuration>
EventEvaluatorFilter
에서 Groovy 로 필터 조건을 줄수 있는 Evaluator.ILoggingEvent
객체가 e
혹은 event
변수로 전달되며 TRACE
,DEBUG
,…ERROR
도 변수로 전달된다.level
변수는 toInt()
로 숫자로 변환하여 비교할 수 있다. e.level.toInt() >= WARN.toInt()
형태.<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <filter class="ch.qos.logback.core.filter.EvaluatorFilter"> <evaluator class="ch.qos.logback.classic.boolex.GEventEvaluator"> <expression> e.level.toInt() >= WARN.toInt() && <!-- Stands for && in XML --> !(e.mdc?.get("req.userAgent") =~ /Googlebot|msnbot|Yahoo/ ) </expression> </evaluator> <OnMismatch>DENY</OnMismatch> <OnMatch>NEUTRAL</OnMatch> </filter> <encoder> <pattern> %-4relative [%thread] %-5level %logger - %msg%n </pattern> </encoder> </appender>
<configuration> <property name="STACKTRACE_FILTER" value=" 불필요한 stack 문자열 나열, org.junit.platform.engine., org.junit.platform.launcher., org.junit.platform.commons.util.ReflectionUtils., org.junit.jupiter.engine., org.junit.jupiter.params.provider., org.junit.jupiter.api.AssertThrows., org.junit.jupiter.api.AssertDoesNotThrow., org.assertj.core.api.AssertionsFor, org.assertj.core.api.ThrowableAssert., org.gradle. "/> <property name="CONSOLE_LOG_PATTERN" value=".... %exception{full,${STACKTRACE_FILTER}} %n"/>
String.contains()
로 검사한다.