[Springboot] 슬랙으로 로그 남기기(Logback)

Bobby·2021년 9월 16일
1

즐거운 개발일지

목록 보기
8/22
post-thumbnail

Logback을 이용한 로그 남기기

  • SLF4J(Simple Logging Facade for Java)의 구현체 중 하나이다.
  • 스프링 부트에서는 spring-boot-starter 패키지 안에 로그 라이브러리를 기본적으로 가지고 있다. (log4j, logback)
  • 스프링 부트 실행 시 resources 디렉토리 안에 logback-spring.xml 파일이 있으면 참조, 없으면 스프링 부트 기본 설정이 적용된다.
  • 로그 레벨은 TRACE < DEBUG < INFO < WARN < ERROR
  • 각 에러의 종류에 따라 레벨을 설정 하면 된다.
  • 각 레벨 설정은 상위 레벨 포함(ex: info레벨 일 경우 warn, error 레벨 포함)
  • 기본 로그 레벨은 INFO로 설정 되어있고 application.yml(properties)에서 변경 할 수 있다.
    • root는 전체 로깅 레벨을 설정 한다.
    • 각 패키지 별로 설정이 가능하다.
    • 디테일한 경로가 우선순위가 높다.
logging.level:
  root: info
  com.example.log: info
  com.example.log.controller: error
  com.example.log.service: warn

로그 남기기

TestController

  • com.example.log.controller 패키지는 로그레벨을 error로 설정
@RestController
public class TestController {

    @Autowired
    TestService testService;

    Logger log = LoggerFactory.getLogger(TestController.class);

    @GetMapping("/log")
    public String test() {
        log.trace("controller trace log");
        log.debug("controller debug log");
        log.info("controller info log");
        log.warn("controller warn log");
        log.error("controller error log");
        testService.test();
        return "success";
    }
}

TestService

  • com.example.log.service 패키지는 로그레벨을 warn으로 설정
@Service
public class TestService {

    Logger log = LoggerFactory.getLogger(TestService.class);

    public void test() {
        log.trace("service trace log");
        log.debug("service debug log");
        log.info("service info log");
        log.warn("service warn log");
        log.error("service error log");
    }
}

출력

  • 설정한 로그 레벨 대로 출력이 되었다.

로그 설정 커스텀

  • profile 설정 -> 참조
  • logback-spring.xml 파일을 생성하면 스프링부트 기본 로그설정 대신 해당 파일 설정을 로드한다.

logback-spring.xml

  • configuration 안에 설정들을 넣는다.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  
  ... 설정 내용
  
</configuration>

property

  • 중복 사용하는 값들을 변수처럼 사용할 수 있다.
    <!-- 로그 설정 -->
    <property name="LOG_DIR" value="./logs"/>
    <property name="LOG_PATH_NAME" value="${LOG_DIR}/data/"/>
    <property name="ERROR_LOG_PATH_NAME" value="${LOG_DIR}/error/"/>
    <property name="LOG_PATTERN_CONSOLE" value="%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %highlight([ %-5level]) | %cyan(%logger{35}) - %msg%n" />
    <property name="LOG_PATTERN_FILE" value="[%d{yyyy-MM-dd HH:mm:ss}:%-3relative][%thread] %-5level %logger{35} - %msg%n" />
    <property name="MAX_HISTORY" value="365" />

appender

  • 로그메시지를 출력할 대상을 설정한다.
  • 콘솔, 파일, 메일 등등 출력 대상을 설정 할 수 있다. 참조
  • name 으로 구분 지어 원하는 대상을 설정할 수 있다.
  • pattern은 출력될 패턴을 지정한다.
    <!-- 콘솔 출력 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${LOG_PATTERN_CONSOLE}</pattern>
        </encoder>
    </appender>

    <!-- 파일로 저장-->
    <appender name="DATA" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 일자별로 로그파일 적용하기 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH_NAME}data_%d{yyyyMMdd}.log</fileNamePattern>
            <maxHistory>${MAX_HISTORY}</maxHistory> <!-- 일자별 백업파일의 보관기간 -->
        </rollingPolicy>
        <encoder>
            <pattern>${LOG_PATTERN_FILE}</pattern>
        </encoder>
    </appender>

    <!-- 에러의 경우는 별도 파일 저장 -->
    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <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.TimeBasedRollingPolicy"> <!-- .gz,.zip 등을 넣으면 자동 일자별 로그파일 압축가능 -->
            <fileNamePattern>${ERROR_LOG_PATH_NAME}error_%d{yyyyMMdd}.log</fileNamePattern>
            <maxHistory>${MAX_HISTORY}</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${LOG_PATTERN_FILE}</pattern>
        </encoder>
    </appender>

logger

  • 설정한 appender들의 출력 레벨과 패키지등을 설정 한다.
  • springProfile을 통해 profile 별로 원하는 동작을 지정 할 수 있다.
    <!-- logger 설정 -->
    <springProfile name="dev, prod">
        <logger name="com.example.log" level="INFO" additivity="false">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="DATA"/>
        </logger>
        <logger name="com.example.log" level="ERROR" additivity="false">
            <appender-ref ref="ERROR"/>
        </logger>
    </springProfile>

    <!-- 위의 logger 에 해당하지 않으면 기본 설정 -->
    <root level="INFO">
        <appender-ref ref="DATA"/>
        <appender-ref ref="STDOUT"/>
    </root>
    <root level="error">
        <appender-ref ref="ERROR" />
    </root>

테스트

  • STDOUT appender 의 패턴대로 콘솔에 출력
  • DATA, ERROR appender 설정에 따라 파일 생성

에러 로그 슬랙으로 전달하기

1. 슬랙 설정

  • 개발 서버와 운영 서버 별로 따로 로그를 남기기 위해 슬랙 채널 두개 생성했다.

  • 서버와 연동하기 위해 웹 훅 설치가 필요하다.

  • 로그를 외부에서 슬랙으로 가져오는 것이니 Incomming WebHooks를 설치 하도록 한다.

  • 이렇게 웹훅이 생성 된다.

  • 밑으로 내려보면 여러 설정을 할 수 있다.

  • 두 채널 각각 추가 하도록 한다.


2. 프로젝트 생성

  • spring initializer : spring boot 2.5.4
  • dependency
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'com.github.maricn:logback-slack-appender:1.4.0'    

프로젝트 구조


3. logback-spring.xml 추가하기

  • profile이 dev, prod 일 때 사용할 SLACK_ERROR apender 추가
  • property에서 외부 파일을 참조하여 값을 사용할 수 있다.

slack-logback.yml(dev)

webhook-uri: {dev 슬랙 webhook-uri}
channel: test_dev
username: dev TEST ERROR LOG
emoji: eyes

slack-logback.yml(prod)

webhook-uri: {prod 슬랙 webhook-uri}
channel: test_prod
username: prod TEST ERROR LOG
emoji: eyes

logback-spring.xml 추가

  • webhookUri : 슬랙의 webhook uri
  • channel : 슬랙의 채널이름(# 포함)
  • username : 메시지 보낼 이름
  • iconEmoji : 이모지 출력
  • colorCoding : 로그 레벨 색을 설정했다면 출력
  • filter 로 ERROR 레벨의 경우에만 전송

...

    <!-- profile 에 따라 slack 에 전송 -->
    <springProfile name="dev, prod">
        <property resource="slack-logback.yml" />
        <appender name="SLACK_ERROR" class="com.github.maricn.logback.SlackAppender">
            <webhookUri>${webhook-uri}</webhookUri>
            <channel>#${channel}</channel>
            <layout class="ch.qos.logback.classic.PatternLayout">
                <pattern>${LOG_PATTERN_FILE}</pattern>
            </layout>
            <username>${username}</username>
            <iconEmoji>:${emoji}:</iconEmoji>
            <colorCoding>true</colorCoding>
        </appender>
        <appender name="ASYNC_SLACK_ERROR" class="ch.qos.logback.classic.AsyncAppender">
            <appender-ref ref="SLACK_ERROR"/>
            <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
                <level>ERROR</level>
            </filter>
        </appender>
    </springProfile>

    <!-- logger 설정 -->
    <springProfile name="dev, prod">
        <logger name="com.example.log" level="INFO" additivity="false">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="DATA"/>
        </logger>
        <logger name="com.example.log" level="ERROR" additivity="false">
            <appender-ref ref="ERROR"/>
            <appender-ref ref="ASYNC_SLACK_ERROR"/> <!-- 추가 -->
        </logger>
    </springProfile>

...

4. 빌드 및 테스트

dev 테스트

./gradlew clean bootjar -Pprofile=dev

java -jar build/libs/log-0.0.1-SNAPSHOT.jar

prod 테스트

./gradlew clean bootjar -Pprofile=prod

java -jar build/libs/log-0.0.1-SNAPSHOT.jar


참고

profile
물흐르듯 개발하다 대박나기

0개의 댓글