logback

Welcome to Seoyun Dev Log·2024년 10월 8일
0

[WORK] 학습내용

목록 보기
25/25

운영을 위해서는 로그는 반드시 필요하다

데이터는 돈이고 로그는 값비싼 자산이다. 유저들의 패턴이나 행동을 파악 데이터가 된다

📌 로그를 찍는것은 데이터 내용이 외부로 노출되지 않아야한다.
내부에서 개발을 위한 데이터의 경우 article id 같은 내용을 찍어도 괜찮지만
아니면 외부로 노출하지 말아야함.

SLF4J

logging framwork이다.

Appender

  • consoleAppender: 콘솔에 log 출력
  • FileAppender: 파일 단위로 log 저장
  • RollingFileAppender: (설정 옵션에 따라) log 를 여러 파일로 나누어 저장
    • 파일에 로그를 출력해서 저장
    • 하나의 파일에 모든 로그를 저장하는 것이 아니라 여러 파일로 나누어 관리
    • 설정 옵션에 따라서 파일의 명칭, 삭제 기간, 수정 등을 할 수 있다.
    • 운영 서버에서는 무조건 파일 어펜더를 사용한다
    • 하루가 지나면 파일뒤에 서픽스 글자가 붙어서 정렬해주는 기능 등
  • SMTPAppender: log를 메일로 전송하여 기록
  • DBAppender: log를 DB에 저장

local 환경 logback (console)

  1. resources 폴더에 logback-spring.xml 파일을 생성한다

    • 이는 하위의 로그백을 만들어주게될 경우 부모 logback 같은 역할을 하게된다
  2. xml파일에 <? 자동완성, configuration 설정을 하게 되면 springboot 서버를 처음 띄울때 나오는 log를 덮어씌우게 된다. 이는 해당 xml 파일을 만들경우 기존의 logback를 무시하고 가장 최우선으로 적용되기 때문이다

    <?xml version="1.0" encoding="UTF-8" ?>
    <configuration>
    
    </configuration>

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
		기본 스프링 디폴트 로그백 (shift 두번 누르고 path 붙여서 확인해볼것)
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <include resource="logback-spring-${spring.profiles.active}.xml"/>
</configuration>

<included>
    <include resource="org/springframework/boot/logging/logback/console-appender.xml"></include>

    <!--<included>
        <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>${CONSOLE_LOG_PATTERN}</pattern>
                <charset>${CONSOLE_LOG_CHARSET}</charset>
            </encoder>
        </appender>
    </included>-->

    <appender name="CONSOLE2" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>INFO</level>
        </filter>
        <layout>
            <pattern>
                [CONSOLE2] [%-5level] %d{yyyy-MM-dd HH:mm:ss} [%thread] [%logger{0}:%line] -%msg%n
            </pattern>
        </layout>
    </appender>

    <root level="DEBUG">
<!--        <appender-ref ref="CONSOLE"/>-->
        <!--spring logback에 있는 console name을 찾아서 실행-->
        <appender-ref ref="CONSOLE2"/>
    </root>
</included>
package dev.be.logback.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
public class DemoController {

    @GetMapping("/demo")
    public String demo() {
log.trace("log -> trace");
log.debug("log -> debug");
log.info("log -> info");
log.warn("log -> warn");
log.error("log -> error");
        return "demo";
    }
}
 

설정한 log level에 맞게 로그가 출력되는지 확인할 것

프로덕션 환경

https://medium.com/dong-gle/로깅-정책-768c658f0f8d

https://ckddn9496.tistory.com/82

  • Active profile 환경에 따라서 로그 세팅이 돌아가도록 생성했다.
  • 중복되는 패턴이나 경로값을 properties에 따로 지정하여 사용한다

logback-variables.properties

# 중복되는 출력 패턴값과 경로를 지정하여 사용해준다

LOG_DIR=logs
LOG_PATTERN=[%-5level] %d{yyyy-MM-dd HH:mm:ss} [%thread] [%logger{0}:%line] - %msg%n
<included>

    <property resource="logback-variables.properties">

    </property>
    <appender name="REQUEST1" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--파일은 관리를 위해서 동일한 경로에서 관리를 해야한다-->
        <file>**${LOG_DIR}**/request1.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--지정한 시간이 지나면 archive 디렉토리 하위 아래 reqeust1, 날짜, 01234 ~ 순서를 지정해주고 하나의 파일로 압축하는 것-->
            <fileNamePattern>${LOG_DIR}/archive/request1.%d{yyyy-MM-dd}_%i.log</fileNamePattern>
            <!--로그 파일 최대 크기-->
            <maxFileSize>1KB</maxFileSize>
            <!--로그 파일 최대 보관주기 단위: 일-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>
                [REQUEST1] **${LOG_PATTERN}**
            </pattern>
            <outputPatternAsHeader>true</outputPatternAsHeader>
        </encoder>
    </appender>

    <appender name="REQUEST2" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--파일은 관리를 위해서 동일한 경로에서 관리를 해야한다-->
        <file>${LOG_DIR}/request2.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--지정한 시간이 지나면 archive 디렉토리 하위 아래 reqeust1, 날짜, 01234 ~ 순서를 지정해주고 하나의 파일로 압축하는 것-->
            <fileNamePattern>${LOG_DIR}/archive/request2.%d{yyyy-MM-dd}_%i.log</fileNamePattern>
            <!--로그 파일 최대 크기-->
            <maxFileSize>1KB</maxFileSize>
            <!--로그 파일 최대 보관주기 단위: 일-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>
                [REQUEST2] [%-5level] ${LOG_PATTERN}
            </pattern>
            <outputPatternAsHeader>true</outputPatternAsHeader>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="REQUEST1"/>
        <appender-ref ref="REQUEST2"/>
    </root>
</included>

outputPatternAsHeader

<outputPatternAsHeader>true</outputPatternAsHeader>

ref : https://logback.qos.ch/manual/encoders.html#outputPatternAsHeader

header 부분에 출력 패턴을 확인할 수 있다


https://velog.io/@kjy0302014/Spring-Boot-LogBack-적용하기#logfj-vs-logback


https://velog.io/@kjy0302014/Spring-Boot-LogBack-적용하기#logfj-vs-logback

MDC

Slf4j를 사용하기 때문에 바로 MDC를 호출하여 사용할 수 있다

//멀티스레드 환경에서 로그를 남길때 사용하는 개념
//스레드마다 고유한 로그값을 가지고 있는데 그걸 로그백에 전달해주기 위한 개념
package dev.be.logback.controller;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
public class MdcController {

    @GetMapping("/mdc")
    public String mdc() {
        //멀티스레드 환경에서 로그를 남길때 사용하는 개념
        //스레드마다 고유한 로그값을 가지고 있는데 그걸 로그백에 전달해주기 위한 개념
        MDC.put("job", "dev");

log.trace("log -> trace");
log.debug("log -> debug");
log.info("log -> info");
log.warn("log -> warn");
log.error("log -> error");

        MDC.clear();
        return "mdc";
    }
}
<included>
    <!-- logback-variables.properties에 정의되어 있는 Key를 사용하기 위한 코드 -->
    <property resource="logback-variables.properties">

    </property>
    <appender name="REQUEST1" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--파일은 관리를 위해서 동일한 경로에서 관리를 해야한다-->
        <file>${LOG_DIR}/request1.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--지정한 시간이 지나면 archive 디렉토리 하위 아래 reqeust1, 날짜, 01234 ~ 순서를 지정해주고 하나의 파일로 압축하는 것-->
            <fileNamePattern>${LOG_DIR}/archive/request1.%d{yyyy-MM-dd}_%i.log</fileNamePattern>
            <!--로그 파일 최대 크기-->
            <maxFileSize>1KB</maxFileSize>
            <!--로그 파일 최대 보관주기 단위: 일-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>
                [REQUEST1] ${LOG_PATTERN}
            </pattern>
            <outputPatternAsHeader>true</outputPatternAsHeader>
        </encoder>
    </appender>

    <appender name="REQUEST2" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--파일은 관리를 위해서 동일한 경로에서 관리를 해야한다-->
        <file>${LOG_DIR}/request2.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--지정한 시간이 지나면 archive 디렉토리 하위 아래 reqeust1, 날짜, 01234 ~ 순서를 지정해주고 하나의 파일로 압축하는 것-->
            <fileNamePattern>${LOG_DIR}/archive/request2.%d{yyyy-MM-dd}_%i.log</fileNamePattern>
            <!--로그 파일 최대 크기-->
            <maxFileSize>1KB</maxFileSize>
            <!--로그 파일 최대 보관주기 단위: 일-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>
                [REQUEST2] [%-5level] ${LOG_PATTERN}
            </pattern>
            <outputPatternAsHeader>true</outputPatternAsHeader>
        </encoder>
    </appender>

    <appender name="MDC" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--파일은 관리를 위해서 동일한 경로에서 관리를 해야한다-->
        <file>${LOG_DIR}/mdc.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--지정한 시간이 지나면 archive 디렉토리 하위 아래 reqeust1, 날짜, 01234 ~ 순서를 지정해주고 하나의 파일로 압축하는 것-->
            <fileNamePattern>${LOG_DIR}/archive/mdc.%d{yyyy-MM-dd}_%i.log</fileNamePattern>
            <!--로그 파일 최대 크기-->
            <maxFileSize>1KB</maxFileSize>
            <!--로그 파일 최대 보관주기 단위: 일-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>
                [MDC] %X{job}%n
            </pattern>
            <outputPatternAsHeader>true</outputPatternAsHeader>
        </encoder>
    </appender>

    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--파일은 관리를 위해서 동일한 경로에서 관리를 해야한다-->
        <file>${LOG_DIR}/error.log</file>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>error</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--지정한 시간이 지나면 archive 디렉토리 하위 아래 reqeust1, 날짜, 01234 ~ 순서를 지정해주고 하나의 파일로 압축하는 것-->
            <fileNamePattern>${LOG_DIR}/archive/error.%d{yyyy-MM-dd}_%i.log</fileNamePattern>
            <!--로그 파일 최대 크기-->
            <maxFileSize>1KB</maxFileSize>
            <!--로그 파일 최대 보관주기 단위: 일-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>
                [ERROR] ${LOG_PATTERN}
            </pattern>
            <outputPatternAsHeader>true</outputPatternAsHeader>
        </encoder>
    </appender>

    <root level="INFO">
        <!--<appender-ref ref="REQUEST1"/>
        <appender-ref ref="REQUEST2"/>-->
        <!--<appender-ref ref="MDC"/>-->
        <appender-ref ref="ERROR"/>
    </root>
</included>
			<filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>error</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
      </filter>

filter를 설정하여 log level을 지정해준다.

onMatch를 설정하는 이유는 warn으로 할 경우 더 높은 레벨이 존재하기 때문에 지정한 로그만 남기기 위해서 지정 로그는 남기고 onMismatch인 경우에는 무시하는 설정이다


Query

뱔도의 고립된 logger를 지정해주는 방법

Slf4j topic을 지정해 줘야한다.

package dev.be.logback.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j(topic = "SQL_LOG1")
@RestController
public class QueryController {

    @GetMapping("/query1")
    public String query() {
log.trace("log -> trace");
log.debug("log -> debug");
log.info("log -> info");
log.warn("log -> warn");
log.error("log -> error");

        return "query1";
    }

}
<included>
    <!-- logback-variables.properties에 정의되어 있는 Key를 사용하기 위한 코드 -->
    <property resource="logback-variables.properties">

    </property>
    <appender name="REQUEST1" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--파일은 관리를 위해서 동일한 경로에서 관리를 해야한다-->
        <file>${LOG_DIR}/request1.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--지정한 시간이 지나면 archive 디렉토리 하위 아래 reqeust1, 날짜, 01234 ~ 순서를 지정해주고 하나의 파일로 압축하는 것-->
            <fileNamePattern>${LOG_DIR}/archive/request1.%d{yyyy-MM-dd}_%i.log</fileNamePattern>
            <!--로그 파일 최대 크기-->
            <maxFileSize>1KB</maxFileSize>
            <!--로그 파일 최대 보관주기 단위: 일-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>
                [REQUEST1] ${LOG_PATTERN}
            </pattern>
            <outputPatternAsHeader>true</outputPatternAsHeader>
        </encoder>
    </appender>

    <appender name="REQUEST2" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--파일은 관리를 위해서 동일한 경로에서 관리를 해야한다-->
        <file>${LOG_DIR}/request2.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--지정한 시간이 지나면 archive 디렉토리 하위 아래 reqeust1, 날짜, 01234 ~ 순서를 지정해주고 하나의 파일로 압축하는 것-->
            <fileNamePattern>${LOG_DIR}/archive/request2.%d{yyyy-MM-dd}_%i.log</fileNamePattern>
            <!--로그 파일 최대 크기-->
            <maxFileSize>1KB</maxFileSize>
            <!--로그 파일 최대 보관주기 단위: 일-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>
                [REQUEST2] [%-5level] ${LOG_PATTERN}
            </pattern>
            <outputPatternAsHeader>true</outputPatternAsHeader>
        </encoder>
    </appender>

    <appender name="MDC" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--파일은 관리를 위해서 동일한 경로에서 관리를 해야한다-->
        <file>${LOG_DIR}/mdc.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--지정한 시간이 지나면 archive 디렉토리 하위 아래 reqeust1, 날짜, 01234 ~ 순서를 지정해주고 하나의 파일로 압축하는 것-->
            <fileNamePattern>${LOG_DIR}/archive/mdc.%d{yyyy-MM-dd}_%i.log</fileNamePattern>
            <!--로그 파일 최대 크기-->
            <maxFileSize>1KB</maxFileSize>
            <!--로그 파일 최대 보관주기 단위: 일-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>
                [MDC] %X{job}%n
            </pattern>
            <outputPatternAsHeader>true</outputPatternAsHeader>
        </encoder>
    </appender>

    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--파일은 관리를 위해서 동일한 경로에서 관리를 해야한다-->
        <file>${LOG_DIR}/error.log</file>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>error</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--지정한 시간이 지나면 archive 디렉토리 하위 아래 reqeust1, 날짜, 01234 ~ 순서를 지정해주고 하나의 파일로 압축하는 것-->
            <fileNamePattern>${LOG_DIR}/archive/error.%d{yyyy-MM-dd}_%i.log</fileNamePattern>
            <!--로그 파일 최대 크기-->
            <maxFileSize>1KB</maxFileSize>
            <!--로그 파일 최대 보관주기 단위: 일-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>
                [ERROR] ${LOG_PATTERN}
            </pattern>
            <outputPatternAsHeader>true</outputPatternAsHeader>
        </encoder>
    </appender>

    <appender name="QUERY" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!--파일은 관리를 위해서 동일한 경로에서 관리를 해야한다-->
        <file>${LOG_DIR}/query.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--지정한 시간이 지나면 archive 디렉토리 하위 아래 reqeust1, 날짜, 01234 ~ 순서를 지정해주고 하나의 파일로 압축하는 것-->
            <fileNamePattern>${LOG_DIR}/archive/query.%d{yyyy-MM-dd}_%i.log</fileNamePattern>
            <!--로그 파일 최대 크기-->
            <maxFileSize>1KB</maxFileSize>
            <!--로그 파일 최대 보관주기 단위: 일-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>
                [QUERY] [%-5level] ${LOG_PATTERN}
            </pattern>
            <outputPatternAsHeader>true</outputPatternAsHeader>
        </encoder>
    </appender>

    <root level="INFO">
        <!--<appender-ref ref="REQUEST1"/>
        <appender-ref ref="REQUEST2"/>-->
        <!--<appender-ref ref="MDC"/>-->
        <!--<appender-ref ref="ERROR"/>-->
    </root>

    <!--logger를 지정을 했지만 이것보다 상위 logger 속성을 받는다고 하면 merge가 되는것
    따라서 합집한 느낌으로 되기때문에 아예 별도의 고립된 설정을 지정한다.-->
    <logger name="SQL_LOG1" level="INFO" additivitty="false">
        <appender-ref ref="QUERY"/>
    </logger>

    <logger name="SQL_LOG2" level="INFO" additivitty="false">
        <appender-ref ref="QUERY"/>
    </logger>
</included>

Slf4j를 사용하지 않고 Logger를 설정하는 방법

package dev.be.logback.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class QueryController2 {
    public static final Loggerlog= LoggerFactory.getLogger("SQL_LOG2");

    @GetMapping("/query2")
    public String query2() {
log.trace("log -> trace");
log.debug("log -> debug");
log.info("log -> info");
log.warn("log -> warn");
log.error("log -> error");
        return "query2";
    }
}
profile
하루 일지 보단 행동 고찰 과정에 대한 개발 블로그

0개의 댓글