Spring Boot에서 Sentry, Slack 연동하기

Sentry 시작하기

Sentry는 애플리케이션에서 발생하는 로그를 수집하고 특정 조건에 따라 slack 등으로 알람을 보낼 수 있는 솔루션입니다. 또한 로그에서 오류 발생 위치나 요청 URL, 요청 brower 정보 등 다양한 정보를 수집할 수 있어 오류 분석에 도움이 됩니다.

Sentry는 클라우드 버전과 설치형(On-Premise)버전이 있습니다. 클라우드 버전은 인프라와 솔루션을 제공하기 때문에 편리하게 사용가능하지만 버전에 따라 금액이 책정될 수 있습니다. 무료 버전은 개발자 혼자 사용하고 특정 기능의 제약이 있을 수 있습니다. 설치형은 인프라 구축, 운영을 직접해야 되지만 민감한 정보가 외부로 유출되는 것을 막을 수 있습니다. 여기서는 테스트를 위해 무료 클라우드 버전을 사용 해보겠습니다.

image-20210614161101009

https://sentry.io/signup/ 에서 회원가입을 하여 로그인 합니다.

계정관리에서 Timezone을 서울로 변경합니다.

image-20210623154022691

SpringBoot Sentry 설정 방법

springframework 프로젝트 설정 방법은 아래쪽에서 설명합니다.

image-20210614150327879

image-20210614145847366

Sentry의 SpringBoot 연동은 버전 2.1.0 이상 지원이 됩니다.

Gradle

implementation 'io.sentry:sentry-logback:5.6.2'
implementation 'io.sentry:sentry-spring-boot-starter:5.6.2'

SpringBoot - sentry 설정

application.yml 파일에 DSN을 추가합니다.

DSN(Client Key)은 프로젝트 최초 생성 시 안내 화면 또는 Settings > Project > Client Keys에서도 확인할 수 있습니다.

sentry:
  dsn: https://56de5b525b004f0a98a843d430bad707@...
  traces-sample-rate: 1.0
  send-default-pii: true
  logging:
    enabled: false
    minimum-event-level: error

traces-sample-rate : 1.0 to capture 100% of transactions for performance monitoring

minimum-event-level : sentry issue로 발생시킬 최소 log level

send-default-pii: sentry issue 상세페이지에서 사용자 정보 표시여부(현재 로그인 id, ip정보)

enabled: false true이면 자동으로 sentry 전송. false면 logback에 설정된 profile에 따라 전송할 수 있음.

SpringBoot - logback 설정

https://docs.sentry.io/platforms/java/guides/spring-boot/logging-frameworks/

logback-spring.xml

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

<configuration>
  <springProperty  name="LOG_INFO_PATTERN" source="logging.info-pattern" />
  <springProperty  name="LOG_ERROR_PATTERN" source="logging.error-pattern" />

  <!-- Slack -->
  <appender name="SENTRY" class="io.sentry.logback.SentryAppender" />

  <!--INFO 로그 콘솔 출력 설정-->
   <appender name="INFO_SOUT" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
        <level>INFO</level>
        <onMatch>ACCEPT</onMatch>
        <onMismatch>DENY</onMismatch>
    </filter>
    <encoder>
      <pattern>${LOG_INFO_PATTERN}</pattern>
    </encoder>
  </appender>

  <!--오류 로그 콘솔 출력 설정-->
  <appender name="ERROR_SOUT" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>ERROR</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>
    <encoder>
      <pattern>${LOG_ERROR_PATTERN}</pattern>
    </encoder>
  </appender>


  <!-- 로컬 환경 -->
  <springProfile name="local">
    <root level="INFO">
      <appender-ref ref="INFO_SOUT" />
      <appender-ref ref="ERROR_SOUT" />
    </root>
  </springProfile>

  <!-- 개발서버 환경 -->
  <springProfile name="dev">
    <root level="INFO">
      <appender-ref ref="INFO_SOUT" />
      <appender-ref ref="ERROR_SOUT" />
    </root>
  </springProfile>

  <!-- 운영 환경 -->
  <springProfile name="prod">
    <root level="INFO">
      <appender-ref ref="SENTRY" />
      <appender-ref ref="INFO_SOUT" />
      <appender-ref ref="ERROR_SOUT" />
    </root>
  </springProfile>

</configuration>

SpringBoot - Sentry 테스트

@Controller
public class PostalController {
@GetMapping(value="/sentryTest")
public void sentryTest() {
	throw new FailResponseApiException("Error!! Sentry Test!!");
}
@ControllerAdvice
public class CommonExceptionHandler {
    private static final String ERROR_PAGE = "error/dispatcher-internal-error";

    @ExceptionHandler(FailResponseApiException.class)
    public String handleFailResponseApiException(FailResponseApiException e, Model model) {
        log.error(e.getMessage(), e);
        model.addAttribute(CommonUtil.ERROR_MSSAGE_CODE, ExceptionType.FAIL_RESPONSE_API);
        return ERROR_PAGE;
    }
    ...
}

브라우저에서 http://localhost:8080/sentryTest를 호출합니다.

센트리 프로젝트 홈에서 Issues를 확인합니다.

image-20210614160431600

상세 페이지에서 오류메시지, 오류 코드 위치, 요청 URL, 요청 클라이언트 정보 등을 볼 수 있습니다.

image-20210614160555355

Springframework에서 Sentry 설정 방법

프로젝트 생성하기 - 플랫폼 선택화면에서 Java를 선택하면 되고, java 1.8 이상 추천하며

상세 설명은 https://docs.sentry.io/platforms/java/ 를 참조하세요.

java 1.7버전은 설정관련 정보는 https://docs.sentry.io/platforms/java/legacy/ 를 참조할 수 있습니다.

image-20210702101137375

Springframework - sentry 설정

maven에 dependency를 추가합니다.

<dependency>
    <groupId>io.sentry</groupId>
    <artifactId>sentry-spring</artifactId>
    <version>1.7.30</version>
</dependency>
<dependency>
    <groupId>io.sentry</groupId>
    <artifactId>sentry-logback</artifactId>
    <version>1.7.30</version>
</dependency>

/src/main/resources/sentry.properties 파일을 생성하고 DSN코드 넣고 저장합니다.

DSN(Client Key)은 프로젝트 최초 생성 시 안내 화면 또는 Settings > Project > Client Keys에서도 확인할 수 있습니다.

dsn=https://abcf6dadf9934942855bdbcc7ec6b5ff@...

Config 클래스를 생성합니다.

package kdr.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;
import io.sentry.spring.SentryExceptionResolver;

@Configuration
public class SentryConfig {
    @Bean
    public HandlerExceptionResolver sentryExceptionResolver() {
        return new SentryExceptionResolver();
    }
}

테스트 시에 아래와 같은 오류가 발생한다면?

io.sentry.connection.ConnectionException: An exception occurred while submitting the event to the Sentry server.
....
Caused by: sun.security.validator.ValidatorException: PKIX path building failed

java 1.7 또는 java 1.8(8u202 and earlier) 버전의 경우 sentry 인증서를 처리 못하여 발생하는 오류입니다.

이를 해결하기 위해서는 아래와 같은 순서로 작업하면 됩니다.

  1. chrome(안될 시 네이버 웨일)에서 sentry의 DSN 주소로 접속한 다음 인증서 내보내기.

    image-20210702111437657

    image-20210702111603866

    image-20210702111632176

  2. java bin경로에 인증서를 copy하고 cmd관리자모드에서 아래 명령 실행.

    다운받은 sentry.cer 파일을 jre/lib/security/ 경로로 옮기고 해당 디렉토리의 cacerts 파일은 백업해두고 실행하는 것이 안전합니다.

    bin> keytool -import -alias sentry -keystore  "C:\Program Files\Java\jdk1.7.0_80\jre\lib\security\cacerts" -file sentry.cer
    또는
    C:\Program Files\Java\jdk1.7.0_80\jre\bin>keytool -importcert -file "C:/Program Files/Java/jdk1.7.0_80/jre/lib/security/sentry.cer" -alias psentryroduct -keystore "C:/Program Files/Java/jdk1.7.0_80/jre/lib/security/cacerts"
       
    키 저장소 비밀번호 입력: changeit
    소유자: CN=*.ingest.sentry.io
    발행자: CN=R3, O=Let's Encrypt, C=US
    ...
    이 인증서를 신뢰합니까? [아니오]:  예
    인증서가 키 저장소에 추가되었습니다.
    
  3. 재시도(동일 오류 발생 시 재부팅 후 재시도.)

참고: https://stackoverflow.com/a/36427118

오류 알림 Slack으로 받기

Slack 좌측 메뉴바에서 채널추가를 눌러 Sentry에서 알람을 받을 채널 하나를 만듭니다.

image-20210622170232313

settings - Integrations - Slack을 추가합니다.

image-20210622165720825

프로젝트 상세 페이지에서 Create Alert를 클릭합니다.

image-20210622165851267

Set Conditions를 클릭합니다.

image-20210622165921520

기본정보 Alert 조건을 설정하고 알람을 받을 Slack정보를 기입합니다.

image-20210622170044224

image-20210622170959144

위에서 작성한 오류 테스트용 /sentryTest를 호출하여 slack에 추가한 채널을 확인합니다.

(주의: 위에서 Set action interval 이내 동일한 오류는 alerting되지 않습니다.)

image-20210622170542594

여기까지 Spring에서 발생한 오류를 Sentry로 전송하고 Alert 기능으로 Slack에게 메시지를 전송하는 것 까지 해보았습니다.

Java 1.7에서 Slack 메시지 전송 시 다음과 같은 오류가 발생할 수 있습니다

javax.net.ssl.SSLException: Received fatal alert: protocol_version

Runtime 시 다음 옵션 추가.

-Dhttps.protocols=TLSv1.2

eclipse 내 tomcat 테스트 시에는 Run - Run Configurations - Arguments탭 - VM arguments에 추가.

intellij의 경우에는 Help -> Edit Custom VM Options

댓글남기기