서비스를 개발하고 운영하면서 필요했던 클라이언트의 에러 로그 트래킹 시스템 도입을 정리
SPA(Single Page Application) + CSR(Client Side Rendering)로 구성된 서비스들이 많아지고 있습니다. 서비스를 운영하다보면 개발자의 예상과는 다르게 예기치 못한 오류가 발생하게됩니다. 서버 사이드 에러가 아닌 클라이언트 단에서 발생한 에러는 어떻게 파악할 수 있을까?
프론트엔드 개발자의 입장에서 클라이언트 단의 오류를 파악하는 가장 확실한 방법은 해당 브라우저의 개발자 도구 콘솔을 통해 오류 내용을 파악하는 것.
이런 번거로운 상황을 만드지 않고 개발자가 직접 프론트엔드(클라이언트 단)의 오류를 트래킹 할 수 있다면 좀 덜 수고스럽게 이슈 대응을 할 수 있지 않은까?
Sentry는 어플리케이션에서 오류가 발생하면 알려주는 에러 트래킹 서비스입니다. (무료 혹은 유료) 클라이언트의 오류 발생시 메일을 보내주고, 슬랙과 연동하면 슬랙 메시지를 통해 오류 발생과 해당 오류에 대한 정보 파악이 가능합니다.
Javascript, vue.js, java, python 등의 다양한 언어, 프레임워크, 라이브러리를 지원하여 여러 프로젝트의 이슈를 한 곳에서 관리함으로써 에러 모니터링을 일원화 할 수 있습니다.
Sentry에 가입 후 프로젝트를 생성한다.
@sentry/browser, @sentry/tracing
# Using yarn
$ yarn add @sentry/node @sentry/tracing
# Using npm
$ npm install --save @sentry/node @sentry/tracing
Sentry 설치 가이드에 따라 코드를 입력합니다. 가능하면 페이지가 로드되는 시점에 코드가 실행될 수 있도록 합니다.
index.js:
const Sentry = require("@sentry/node");
// or use es6 import statements
// import * as Sentry from '@sentry/node';
const Tracing = require("@sentry/tracing");
// or use es6 import statements
// import * as Tracing from '@sentry/tracing';
Sentry.init({
dsn: "여기에 dsn 키값이 들어갑니다.",
// Set tracesSampleRate to 1.0 to capture 100%
// of transactions for performance monitoring.
// We recommend adjusting this value in production
tracesSampleRate: 1.0,
});
const transaction = Sentry.startTransaction({
op: "test",
name: "My First Test Transaction",
});
setTimeout(() => {
try {
foo();
} catch (e) {
Sentry.captureException(e);
} finally {
transaction.finish();
}
}, 99);
위 코드를 실행합니다. 위 코드를 보면 foo()
메소드가 정의되어있지않습니다. 따라서 에러가 발생합니다. 해당 에러는 Sentry에 접속하면 모니터링 할 수 있습니다.
현재 Sentry는 많은 Integrations 지원합니다. 그 중에서 텔레그램은 지원하지 않습니다. 현재 진행중인 프로젝트의 메신저는 텔레그램을 사용중이기 때문에 텔레그램과 연결해 보겠습니다. axios를 사용해서 api를 싸주는 방법을 사용합니다.
텔레그램 봇을 만듭니다.
텔레그램 봇을 만드는 방법은 이전에 써놓은 포스트를 참고해주시면 좋겠습니다.
에러가 Sentry에 전송되기 전에 hook을 이용해서 Error message를 telegram에 전송합니다.
const Sentry = require('@sentry/node');
// or use es6 import statements
// import * as Sentry from '@sentry/node';
const Tracing = require('@sentry/tracing');
// or use es6 import statements
// import * as Tracing from '@sentry/tracing';
const axios = require('axios');
const apiToken = '여기에 telegram http api token이 들어갑니다.'
Sentry.init({
dsn: '여기에 dsn 키값이 들어갑니다.',
// Set tracesSampleRate to 1.0 to capture 100%
// of transactions for performance monitoring.
// We recommend adjusting this value in production
tracesSampleRate: 1.0,
beforeSend: (event, hint) => _sendErrorMessage(event, hint), // 에러를 Sentry에게 전달하기 전 처리할 수 있는 hook
});
const _sendErrorMessage = (event, hint) => {
let errorMsg = 'Sentry error hook';
// const vue = event.contexts.vue;
const hintMsg = hint.originalException || hint.syntheticException;
errorMsg = `[Error]: \n
>>> Message: ${hintMsg.message}\n`
const body = {
chat_id: 'chat_id', // 텔레그램의 CHAT_ID
text: errorMsg,
};
axios({
method: 'POST',
url: `https://api.telegram.org/bot${apiToken}/sendMessage`,
headers: {
'Content-Type': 'application/json;charset=UTF-8',
},
data: body,
}).then(() => {
console.log('Error logged!', hint.originalException || hint.syntheticException);
});
return event;
};
const transaction = Sentry.startTransaction({
op: 'test',
name: 'My First Test Transaction',
});
setTimeout(() => {
try {
throw new Error('telegram hook');
} catch (e) {
Sentry.captureException(e);
} finally {
transaction.finish();
}
}, 99);
실행시면 다음과 같은 결과를 얻을 수 있습니다.
참고