Logback 으로 쉽고 편리하게 로그 관리를 해볼까요? ⚙️ (techcourse.co.kr)
Spring 로그 설정하기 - Logback (velog.io)
Logback 은 log4j 이후에 출시된 Java 기반 Logging Framework 중 하나로 가장 널리 사용되고 있다. SLF4j 의 구현체이며 Spring Boot 환경이라면 별도의 dependency 추가 없이 기본적으로 포함되어 있다.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.GetMapping;
@RestController
public class LogController {
private final Logger logger = LoggerFactory.getLogger("LoggerController 의 로그");
@GetMapping("/log")
public void log() {
logger.info("로깅 발생!");
}
}
간단한 로그를 찍는 과정은 다음과 같다.
[2021-08-07 18:03:03:7491][http-nio-8080-exec-1] INFO LoggerController 의 로그 - 로깅 발생!
다음과 같은 로그가 찍힌다.
로그 레벨은 5가지가 있고, 다음과 같다.
콘솔 로그의 수준을 변경하는 방법은 application.yml 과 logback-spring.xml 에서 설정하는 방법이 있다. 세부적인 설정을 위해서는 logback-spring.xml 로 관리하는 편이 더 좋다. 설정법을 알아보자.
<?xml version="1.0" encoding="UTF-8"?>
<configuration><!-- 이 곳에 추가할 기능을 넣는다. -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
//appender + 어디에 추가할지
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %-5level %logger{36} - %msg%n</Pattern>
//출력 형식을 지정한다.
</layout>
</appender>
</configuration>
다양한 설정들…<appendername="INFO_LOG"class="ch.qos.logback.core.rolling.RollingFileAppender"><file>./logs/info.log</file>
<!-- 파일을 저장할 경로를 정한다 -->
<filterclass="ch.qos.logback.classic.filter.LevelFilter"><level>INFO</level><onMatch>ACCEPT</onMatch>
<!-- 해당 레벨만 기록한다. -->
<onMismatch>DENY</onMismatch>
<!-- 다른 수준의 레벨은 기록하지 않는다.(상위 레벨도 기록 안함), 상위 수준의 레벨에 대한 기록을 원하면 ACCEPT 로 하면 기록된다. -->
</filter>
<!-- 레벨별 필터링이 필요없을 경우 filter class 관련된 부분을 삭제하면 됨-->
<encoder><pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %-5level %logger{35} - %msg%n</pattern>
<!-- 해당 패턴 네이밍으로 현재 로그가 기록됨 -->
</encoder><rollingPolicyclass="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>./was-logs/info.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<!-- 해당 패턴 네이밍으로 이전 파일이 기록됨 -->
<timeBasedFileNamingAndTriggeringPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><maxFileSize>100MB</maxFileSize> <!-- 한 파일의 최대 용량 -->
</timeBasedFileNamingAndTriggeringPolicy><maxHistory>180</maxHistory>
<!-- 한 파일의 최대 저장 기한 -->
</rollingPolicy></appender>
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="LOGS_PATH" value="./logs"/>
<property name="PAST_LOGS_PATH" value="./was-logs"/>
<!-- <property name="LOGS_PATH" value="/home/ubuntu/logs" />
<property name="PAST_LOGS_PATH" value="/home/ubuntu/was-logs"/> -->
// LOGS/PATH 지정해서 밑에서 바인딩해준다.
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %-5level %logger{36} - %msg%n</Pattern>
</layout>
</appender>
//기본 STDOUT (콘솔에 출력하는 코드)
<appender name="INFO_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${ LOGS_PATH }/info.log</file>
<encoder>
<pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${PAST_LOGS_PATH}/info.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>10</maxHistory>
</rollingPolicy>
</appender>
//info.log 전체 다출력하는 로그
<appender name="ERROR_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${ LOGS_PATH }/error.log</file>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level> //에러 레벨
<onMatch>ACCEPT</onMatch> // 에러 레벨 허용
<onMismatch>DENY</onMismatch> //에러 레벨이 아니면 거부
</filter>
<encoder> //문자 패턴 밑에 더 서술함
<pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
//File Name 경로 (일자 별로 백업 저장)
<fileNamePattern>${PAST_LOGS_PATH}/ERROR.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize> //FILE 최대 사이즈는 10메가
</timeBasedFileNamingAndTriggeringPolicy>
<maxHistory>10</maxHistory> //10일동안 저장
</rollingPolicy>
</appender>
//error.log 전체에서 에러만 출력하는 로그
<include resource="amazon-appender.xml"/>
<include resource="ali-appender.xml"/>
<include resource="ebay-appender.xml"/>
//include로 다른 파일에서 가져옴 (너무 길어서 나눠놓음)
<logger name="AmazonLogger" level="debug" additivity="false">
<appender-ref ref="AmazonReader" /> //AmazonReader appender는 파일로 받아옴
<appender-ref ref="STDOUT" /> //STDOUT은 그냥 콘솔에 출력
</logger>
//기본 level이 debug (개발 단계에서 trace 빼고 다 가져오기 위함
<logger name="AliLogger" level="debug" additivity="false">
<appender-ref ref="AliReader" />
<appender-ref ref="STDOUT" />
</logger>
<logger name="eBayLogger" level="debug" additivity="false">
<appender-ref ref="eBayReader" />
<appender-ref ref="STDOUT" />
</logger>
<root level="INFO">
<appender-ref ref="STDOUT"/>
<appender-ref ref="INFO_LOG" />
<appender-ref ref="ERROR_LOG" />
</root>
// root에서는 전체를 다룸 (STDOUT, INFO_LOG, ERROR_LOG가 기본으로 설정되어있음)
</configuration>
%m : 로그내용이 출력
%p : trace > debug > info > warn > error 등의 priority 출력
%r : 어플리케이션이 시작되어 로깅이벤트가 발생하는 시점까지의 경과시간을 밀리세컨드로 출력
%c : 예) 카테고리가 a.b.c 처럼 되어있다면 %c{2}는 b.c가 출력됩니다.
%n : 플랫폼 종속적인 개행문자가 출력된다. \r\n 또는 \n 일것이다
%d : 로깅이벤트가 일어나 날짜 출력 ( 프로그램의 실행속도를 느리게 한다.)
예) %d{HH:mm:ss} 또는 %d{dd MMMM yyyy HH:mm:ss}
%C : 호출자의 클래스명 출력
예) 클래스구조가 org.apache.xyz.SomeClass 처럼 되어있다면 %C{2}는 xyz.SomeClass 가 출력됩니다
%M : 로깅이 발생한 method 이름을 나타냅니다.
%F : 로깅이 발생한 프로그램 파일명을 나타냅니다.
%l : 로깅이 발생한 caller의 정보를 나타냅니다
%L : 로깅이 발생한 caller의 라인수를 나타냅니다
%x : 로깅이 발생한 thread와 관련된 NDC(nested diagnostic context)를 출력합니다.
%X : 로깅이 발생한 thread와 관련된 MDC(mapped diagnostic context)를 출력합니다.
%% : % 표시를 출력하기 위해 사용한다.
%t : 로그이벤트가 발생된 쓰레드의 이름을 출력합니다
다음과 같이 시간별로 로그가 찍힌다.
warn.log의 메모리 제한이 걸렸거나 일자가 넘어가면
waslog에 기록된다.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// LoggerFactory 사용 시
private static final Logger LOG = LoggerFactory.getLogger(class명.class);
// lombok 사용 시
@Slf4j
public class 클래스명 {
public void 메소드명() {
log.info("...");
}
}