스프링에서는 따로 설정하지 않는한 기본적으로 Apache의 JCL(Jakarta Common Logging)을 사용함

jcl-over-slf4j와 같은 어댑터 역할을 수행하는 라이브러리를 이용해야 logback을 이용 가능
logback-core: Appender와 Layout 인터페이스가 존재하는 모듈logback-classic: logback-core와 SLF4J API 라이브러리를 포함하고 있음(Logger 클래스가 포함된 모듈)logback-access: Servlet Container와 통합되어 HTTP 액세스에 대한 로깅 기능을 제공(Container 레벨에서 사용)Logback을 이용하고 싶은 경우, 아래의 의존성을 추가(Spring 로깅 구조 참고)
//@Slf4j에 필요
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
//logback이랑 logstash 연동
implementation 'net.logstash.logback:logstash-logback-encoder:7.4'
//logback이랑 kafka 연동
implementation group: 'com.github.danielwegener', name: 'logback-kafka-appender', version: '0.2.0-RC2'

Appender 인터페이스를 구현해 이벤트를 처리(Logger는 logging 이벤트를 처리)Logger로 정의한 내용들을 어떻게 처리할 것인지 처리 역할을 위임받은 클래스
Appender는 태그를 통하여 구성되며 name와 class 속성을 필수적으로 가져야만 함

System.err 또는 System.out에 추가예시
<!--System.out에 찍히는 로그 설정-->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"></appender>
OutputStreamAppender의 서브클래스로서 파일에 로그 이벤트를 추가
예시
<!--FILE에 찍히는 로그 설정-->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
FileAppender를 상속하며 파일을 롤오버하는 기능으로 확장예시
<appenders>
<rollingFile name="LogToFile" fileName="logs/application.log"filePattern="logs/application.log.%d{yyyy-MM-dd-hh-mm}">
<patternLayout pattern="${sys:FILE_LOG_PATTERN}" />
<!-- 정책을 통해 로그파일 롤오버 -> 1분마다 로그파일이 생성-->
<policies>
<timeBasedTriggeringPolicy interval="1" modulate="true" />
</policies>
<!-- 기본 롤오버 전략 => 생성된 로그 파일이 3개가 초과될 때 1개 삭제-->
<defaultRolloverStrategy>
<delete basePath="logs" maxDepth="1">
<ifAccumulatedFileCount exceeds="3"/>
</delete></defaultRolloverStrategy>
</rollingFile>
</appenders>
예시
<appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
<smtpHost>rlatkd.smtp.com</smtpHost>
<to>rlatkdgns042@khu.ac.kr</to>
<from>rlatkdgns042@khu.ac.kr</from>
<subject>TESTING: %logger{20} - %m</subject>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%date %-5level %logger{35} - %message%n</pattern>
</layout>
</appender>
<root level="DEBUG">
<!--에러 발생시 이메일 발송 트리거 -->
<appender-ref ref="EMAIL" /
</root>
AppenderBase<ILoggingEvent>를 상속해 클래스를 작성함start() 메소드는 자동으로 실행됨append(ILoggingEvent iLoggingEvent)메소드가 동작을 수행예시
package com.rlatkd.monitoring.utils
public class LoggingAppender extends AppenderBase<ILoggingEvent> {
private static final SimpleDateFormat datetimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
protected void append(ILoggingEvent iLoggingEvent) {
System.out.println(iLoggingEvent.getFormattedMessage());
}
@Override
public void start() {
super.start();
}
}
<!-- GellogerMapper.create 호출시 trace level로 EvidenceLoggingAppender가 이벤트 실행 -->
<appender name="customlog" class="com.EvidenceLoggingAppender"></appender><logger name="test.gelog.GellogerMapper.create" level="trace"><appender-ref ref="customlog"/></logger>
OutputStream에서 바이트 배열로 변환시키는 작업을 수행함logback 0.9.19버전 이후 출시된 Encoder는 Layout과 함께 log 출력값을 정의함LayoutWrappingEncoder는 Encoder와 Layout 간의 격차를 해소해주기 위해 Layout을 wrapping함package ch.qos.logback.core.encoder;
public class LayoutWrappingEncoder<E> extends EncoderBase<E> {
protected Layout<E> layout;
private Charset charset;
public byte[] encode(E event) {
String txt = layout.doLayout(event);
return convertToBytes(txt);
}
private byte[] convertToBytes(String s) {
if (charset == null) {
return s.getBytes();
} else {
return s.getBytes(charset);
}
}
}
Encoder는 Layout이 로그 이벤트를 정의해놓은 형식으로 변환한 문자열에 대해 바이트로 변환해 반환하는 역할을 수행함
outputPatternAsHeader을 활성화 시켜야 이용이 가능함예시
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>rlatkd.log</file>
<encoder>
<pattern>%d %-5level [%thread] %logger{0}: %msg%n</pattern>
<outputPatternAsHeader>true</outputPatternAsHeader>
</encoder>
</appender>
예시
package chapters.layouts;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.LayoutBase;
public class MySampleLayout extends LayoutBase<ILoggingEvent> {
public String doLayout(ILoggingEvent event) {
StringBuffer sbuf = new StringBuffer(128);
sbuf.append(event.getTimeStamp() - event.getLoggingContextVO.getBirthTime());
sbuf.append(" ");
sbuf.append(event.getLevel());
sbuf.append(" [");
sbuf.append(event.getThreadName());
sbuf.append("] ");
sbuf.append(event.getLoggerName();
sbuf.append(" - ");
sbuf.append(event.getFormattedMessage());
sbuf.append(CoreConstants.LINE_SEP);
return sbuf.toString();
}
}
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<!--log 이벤트가 다음 문자열로 들어옴-->
<layout class="chapters.layouts.MySampleLayout" />
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
필터 종류
예시
public class SampleFilter extends Filter<ILoggingEvent> {
@Override
public FilterReply decide(ILoggingEvent event) {
//"sample"이라는 문자열을 포함할 경우 ACCEPT, 아닐 경우 다음 필터 확인
if (event.getMessage().contains("sample")) {
return FilterReply.ACCEPT;
} else {
return FilterReply.NEUTRAL;
}
}
}
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="chapters.filters.SampleFilter" />
<encoder>
<pattern>
%-4relative [%thread] %-5level %logger - %msg%n
</pattern>
</encoder>
</appender>
예시
<!--기본 로그 레벨은 INFO-->
<!--내 프로젝트 패키지 로그 레벨은 DEBUG-->
<logger name="com.rlatkd.monitoring" level="DEBUG" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
<appender-ref ref="KAFKA" />
<!--<appender-ref ref="STASH" />-->
</root>
log level 종류
| 로그 | Level |
|---|---|
| FATAL | 애플리케이션이 이벤트를 발생했거나 중요한 비즈니스 기능 중 하나가 더 이상 작동하지 않는 상태일 경우를 알려주는 로그 Level |
| ERROR | 애플리케이션이 하나 이상의 기능이 제대로 작동하지 않는 문제에 부딪힐 때 사용해야 하는 로그 Level |
| WARN | 애플리케이션이 문제 또는 프로세스에 방해가 될 수 있는 상황에 예기치 않은 일이 발생했음을 나타내는 로그 Level |
| INFO | 애플리케이션이 특정 상태에 들어갔는지 등을 나타내는 표준 로그 Level, 일반적으로 정보제공을 위해 사용 |
| DEBUG | 문제를 해결하는데 필요할 수 있는 정보 제공, 모든 것이 올바르게 정상적으로 동작하는지 확인하기 위해 테스트 환경에서 실행할 경우 사용 |
| TRACE | 애플리케이션의 모든 상황을 완벽하게 파악하는 상황에서 사용, debug의 윗 수준으로 log정보가 매우 상세하게 나타냄 |
https://ckddn9496.tistory.com/79
https://www.baeldung.com/logback
https://www.baeldung.com/log4j2-custom-appender
https://logback.qos.ch/manual/appenders.html
https://tecoble.techcourse.co.kr/post/2021-08-07-logback-tutorial/