Sentry

안녕하세요. 프론트엔드 개발을 하고 있는 gyu입니다. 어반베이스에서는 현재 운영되고 있는 서비스들의 화면과 기능을 개발하고, API 적용, 3D SDK 개발 등의 업무를 진행하고 있습니다.

서비스를 개발하고 운영하면서 꼭 필요했던 클라이언트의 에러 로그 트래킹 시스템 도입기를 정리해보았습니다.


클라이언트 사이드 에러 로그 트래킹이 필요한 이유?

SPA(Single Page Application) + CSR(Client Side Rendering) 로 구성된 서비스들이 많아지고 있습니다. 어반베이스의 서비스들도 대부분 SPA + CSR로 개발 및 운영되고 있는데요. 서비스를 운영하다보면 개발자의 예상과는 다르게 예기치 못한 오류가 발생하게 됩니다. 서버 사이드의 에러가 아닌 클라이언트 단에서 발생한 에러는 어떻게 파악할 수 있을까요?

프론트엔드 개발자의 입장에서 클라이언트 단의 오류를 파악하는 가장 확실한 방법은 해당 브라우저의 개발자 도구 콘솔을 통해 오류 내용을 파악하는 것입니다.

이럴 경우 통상적인 방법으로 아래 두가지가 있습니다만,

  1. 오류가 발생한 클라이언트 장비에 원격 접속해 직접 웹 브라우저를 확인한다.
  2. 서비스를 이용 중인 고객에게 직접 ‘웹 브러우저의 개발자 도구를 열고 > 콘솔에 찍힌 오류내용을 캡쳐해주세요.’ 라는 요구를 한다. (개발자가 아닌 일반인들에게는 굉장히 번거로운 요구..)

이런 번거로운 상황을 만들지 않고 개발자가 직접 프론트엔드(클라이언트 단)의 오류를 트래킹할 수 있다면 좀 덜 수고스럽게 이슈 대응을 할 수 있지 않을까요?


Sentry란?

Sentry는 어플리케이션에서 오류가 발생하면 알려주는 에러 트래킹 서비스입니다. (무료 혹은 유료) 클라이언트의 오류 발생시 메일을 보내주고, 슬랙과 연동하면 슬랙 메시지를 통해 오류 발생과 해당 오류에 대한 정보 파악이 가능합니다.

Javascript, vue.js, node.js, java, python 등의 다양한 언어, 프레임워크, 라이브러리를 지원하여 여러 프로젝트의 이슈를 한 곳에서 관리함으로써 에러 모니터링을 일원화 할 수 있습니다.

[지원하는 언어, 플랫폼 및 인티그레이션]

지원하는 언어 이미지 지원하는 플랫폼 및 인티그레이션



또한 오류를 파악할 수 있는 다양한 정보도 제공합니다.

[오류에 대한 다양한 정보들]

이름 설명
Device 오류가 발생한 장비 정보 (Family(Android, iOS … etc), Model, Architecture, Memory, Capacity, Simulator, BootTime, Timezone)
EXCEPTION 에러가 발생한 코드 라인과 에러 메시지
App 오류가 발생한 어플리케이션 정보 (ID, Start Time, Device, Build Type, Bundle ID, Bundle Name, Version, Build)
Browser 오류가 발생한 브라우저 정보 (Name, Version, Headers)
Operating System 유저가 사용하는 OS (Name, Version, Kernel Version, Rooted)
BREADCRUMBS 유저가 오류 발생시 거친 과정 및 경로



[실제 누적된 Error 정보]

  • 오류에 대한 상세한 정보 및 오류 내용 오류에 대한 요약

  • 오류가 발생한 클라이언트 환경에 대한 정보 오류 발생 환경 정보

  • 오류가 발생한 Vue Component에 대한 정보 오류 발생한 Vue 컴포넌트 정보

[무료 사용시 제한 사항]

  1. 멤버 수 제한 : 하나의 계정으로 로그인해야 해당 이슈들을 조회할 수 있습니다. (유료 사용의 경우 무제한)
  2. 에러 수 제한 : 무료 사용시 5,000개로 제한 (유료 사용시 100,000개 이상 ~ )
  3. 히스토리 저장 : 오류에 대한 히스토리를 30일만 저장 (유료 사용시 90일)
  4. 기타 소소한 추가 기능들은 링크를 통해 확인 가능합니다. Sentry 유료 정책

현재 개발중인 프로젝트에 적용해보기

1) Sentry Vue 용 SDK 설치하기

# Using yarn
$ yarn add @sentry/vue

# Using npm
$ npm install @sentry/vue

2) Vue 컴포넌트에서 에러 발생시 해당 컴포넌트의 이름과 props 정보를 알기위한 tracing 설치하기

# Using yarn
yarn add @sentry/tracing

# Using npm
npm install @sentry/tracing

3) Sentry.io 사이트에서 회원가입하고 프로젝트 생성하여 DSN 키 발급받기

  • 회원가입 회원가입
  • 각 플랫폼에 맞는 프로젝트 생성하기 각 플랫폼에 맞는 프로젝트 생성하기
  • Sentry에서 발급해주는 DSN 값을 예제 코드를 통해 노출 각 플랫폼에 맞는 프로젝트 생성하기

4) 프로젝트 최상위 컴포넌트(앱 진입점)에서 Sentry 선언하기

   import * as Sentry from "@sentry/vue";
   import { Integrations } from "@sentry/tracing";

Sentry SDK 와 vue integration을 선언합니다. 그후 컴포넌트 최상위 마운트 시점에 아래와 같이 초기화 합니다.

5) Sentry 초기화 및 옵션 설정

  Sentry.init({
   Vue,
   dsn: '', // 발급받은 DSN키 입력
   integrations: [new Integrations.BrowserTracing()], // Vue 설정
   tracingOptions: { // 하위 구성 요소를 추적하고 렌더링 프로세스에 대한 자세한 내용을 보기
      trackComponents: true,
   },
   attachProps: true, // 로깅을 위해 모든 Vue 구성 요소의 props를 보기
   tracesSampleRate: 1, // 0에서 1 사이의 숫자로 주어진 트랜잭션이 Sentry로 전송 될 확률을 제어
   beforeSend: (event, hint) => this._sendErrorMessage(event, hint), // 에러를 Sentry에게 전달하기 전 처리할 수 있는 hook
});

각 옵션에 대한 설명은 코드 주석으로 대신하였습니다.

이외에 많은 옵션들은 Sentry 공식 문서를 참고하시어 다양한 설정들을 해보시면 좋을 것 같습니다.


텔레그램으로 Sentry 에러 알림받기

beforeSend 메소드는 에러가 발생하면 Sentry로 넘기기 전에 따로 처리할 게 있다면 추가할 수 있습니다.

현재 설정해 놓은 Sentry는 대표로 설정한 이메일로 에러 알림 메일이 전송됩니다. Slack 메신저에는 이러한 알림을 지원하고 있지만 현재 어반베이스에서 사용 중인 Telegram 메신저는 지원하지 않습니다.

이에 beforeSend 메소드를 직접 선언하여 에러 발생 후 Telegram으로 메시지를 전송하도록 기능을 추가했습니다.

_sendErrorMessage: function(event, hint) {
  let errorMsg = '';

  if (( !event || !event.contexts || !event.contexts.vue ) &&
    ( !hint || !hint.originalException || hint.syntheticException )) {
    return null;
  }

  const vue = event.contexts.vue;
  const hintMsg = hint.originalException || hint.syntheticException;

    errorMsg = `<b>[Error]</b>: \n
        >>> URL: ${htmlEntity(event.request && event.request.url)} \n
        >>> Message: ${htmlEntity(hintMsg.message)}\n
        >>> Method: ${htmlEntity(vue.lifecycleHook)}\n
        >>> At: ${htmlEntity(vue.componentName)}\n
        >>> Props: ${htmlEntity(vue.propsData)}`;

    const body = {
      chat_id: '@UB_CHAT_ID', // 텔레그램의 CHAT_ID
      text: errorMsg,
    };
    axios({
      method: 'POST',
      url: 'https://api.telegram.org/봇아이디/sendMessage',
      headers: {
        'Content-Type': 'application/json;charset=UTF-8',
      },
      data: body,
    }).then(() => {
      console.log('Error logged!', hint.originalException || hint.syntheticException);
    });

  return event;
}

텔레그램 메시지에 전송될 errorMsg 변수 안에는 다음과 같은 내용을 담았습니다.

  • 에러가 발생한 URL
  • 에러 메시지
  • 에러가 발생한 vue 컴포넌트의 라이프사이클 메소드
  • 에러가 발생한 vue 컴포넌트 명
  • 상위로부터 전달받은 props


[실제 전달된 텔레그램 메시지] 각 플랫폼에 맞는 프로젝트 생성하기



[추가적으로 이슈 필터링이 가능한 옵션들] 각 플랫폼에 맞는 프로젝트 생성하기
Sentry의 프로젝트 설정에 들어가면 위와 같이 많은 옵션들로 오류 알림을 필터링 할 수 있습니다. 로컬환경에서는 에러를 안보내도록 설정할 수 있고, 브라우저에 따라 에러를 무시하게끔 셋팅할 수도 있습니다.


현재 어반베이스의 신규 프로젝트들은 클라이언트 이슈 발생 시 개발부문 대표 계정으로 메일 알림을 받고 있고, 텔레그램 메시지를 통해서도 에러 알림이 오도록 설정해 두었습니다.

아직까지는 무료로 제공되는 기능도 충분한 것 같아 유료화 전환보다는 효율적으로 내부 오류 처리 프로세스를 정립해 나가고 있는데요. 훗날 트래픽이 많아지거나 개발자들이 더 많아진다면 유료 전환을 고려해볼 수도 있을 것 같습니다.

클라이언트 오류 발생시 지향하는 내부 오류 처리 프로세스는 다음과 같습니다.

  1. 에러 알림이 많아질 경우, 팀내 공통의 계정을 만들어 모든 팀원이 Sentry에 접근 가능하도록 한다.
  2. 팀내 이슈 담당자를 정해두고 메일이 오면 Sentry를 통해 발생한 에러를 Jira에 등록한다. (Sentry 내에서 Jira연동이 가능)
  3. 텔레그램으로 알림이 온 경우, 본인의 담당 여부를 빠르게 파악하여 담당자에게 알린다.
  4. 등록된 이슈가 해결되면 담당자에게 알리고, 담당자는 해당 에러를 정리한다.(Sentry 내 관리)
  5. 팀 계정이 없고 담당자를 바꿔야할 상황이면 해당 담당자가 새로운 Sentry 계정을 등록하여 관리한다.

현재는 이정도로 사용하고 있고 앞으로도 더 좋은 방법을 고민하고 연구할 생각입니다. 많은 프론트엔드 개발자들이 저희의 Sentry 도입 예시를 참고하셔서, 예기치 못한 클라이언트 이슈 발생의 원인 파악과 해결을 빠르고 수월하게 하셨으면 좋겠습니다~