본문 바로가기
개발/Next.js

[Next] 안정감있는 서비스를 위하여 (Sentry)

by 핸디(Handy) 2023. 1. 12.

들어가며

이번 글에서는 프론트엔드 서비스 안정성을 위해 Next.js 프로젝트에 Sentry(이하 센트리)를 도입하는 과정에 대해 다루도록 하겠습니다.

이후 Sentry의 세부 기능을 이용해서 유의미한 에러 로그를 활용하는 방법에도 알아봅시다.

대상 독자는 

  • Next 프로젝트에 Sentry를 도입하여 유저의 안정성을 향상시키고픈 개발자
  • Sentry 기능을 활용해 좋은 서비스를 만들고 싶은 개발자

Sentry란?

Sentry는 실시간 로그 취합 및 분석 도구, 모니터링 플랫폼입니다. 이미 많은 회사에서도 도입하고 있는 검증된 툴입니다.

프론트엔드를 하다보면 가장 난감할때가 어디선가 들려오는 에러입니다. ( ex. 친구한테 링크 공유했는데 안된데요.. )

유저들의 런타임 환경을 모르기 때문에 이슈를 재연하기가 매우 까다롭습니다. 그렇다고 매번 친구에게 달려가 디바이스를 빌려서 테스트할 수도 없는 상황이구요.

이럴때를 대비하여 에러가 나면 에러가 발생한 코드부터 런타임 환경 등 에러처리에 필요한 정보를 모아주는 서비스가 필요합니다.

이러한 서비스들 중에 가장 유명한 툴이 Sentry입니다.

Sentry FAQs

전통적인 Logging 툴과의 차이점

전통적인 툴은 기본적이고 간단한 정보만 제공합니다. 하지만 센트리는 Exception에 집중하여 aplication crashes를 찾아내어 알려줍니다.

다양한 언어 지원

이건 저도 처음확인한 내용인데, 현업에서 사용되는 거의 모든 언어에 대해 지원하고 있습니다.

 

Platforms

Track errors and performance issues in every language, framework, and library.

sentry.io

Sentry 셋팅

1. Project 생성

2. Project 알람 옵션 셋팅

추후에 설정값 변경이 가능하니 일단은 모든 이슈에 대해 알람으로 설정합시다.

3. Project 이름, 팀 셋팅

Project name은 영어밖에 안되니 유의바랍니다.

4. 코드 셋팅

멋진 서비스답게 앞에서 설정한 플랫폼에 맞춰 next에 설정하는 방법을 알려줍니다.

하나씩 따라가면 되겠습니다.

해당 코드를 입력하면 다음과 같은 파일들이 생깁니다.

npx @sentry/wizard -i nextjs

그리고 설명과 다르게 next.config.js 대신에 next.comfig.wizardcopy.js가 생겼는데 이걸 기존 next.config.js와 merge 시켜줘야합니다. 

5. 결과 확인

생성된 파일을 보면 sentry_sample_error 이라는 page 파일이 생성된 것을 확인할 수 있습니다.

그리고 들어가보면 아래와 같이 기본 페이지가 만들어져 있습니다.

http://localhost:3000/sentry_sample_error

Sentry의 이슈탭에 가보면아이콘에 있는것처럼 에러 이벤트를 기다리고 있는 화면을 볼 수 있습니다.

위의 화면에서 Throw error 버튼을 클릭한 이후 새로고침을 하게 되면 다음과 같은 에러가 생성된 것을 확인할 수 있습니다.

이것으로 Sentry Next 기본 셋팅을 마무리하겠습니다.

Sentry Tip

이젠 Sentry 운영팁에 다루도록 해볼게요.

Sentry는 더욱 강력한 이벤트로깅을 위해 다양한 기능을 제공하고 있습니다.

https://docs.sentry.io/platforms/javascript/guides/nextjs/enriching-events/

모든 기능을 설명할 수는 없으니 공식문서를 천천히 읽어보시길 권장해드리며

이번에는 Scopes and Hubs, Customize Tags, Breadcrumbs 이렇게 3개를 살펴보겠습니다.

Scopes and Hubs

우리의 서비스에서 이벤트가 캡처되어 Sentry로 전송되면 SDK는 해당 이벤트 데이터에 추가정보를 병합하여 내보냅니다.

실제로 네트워크콘솔에서 Sentry로 보내는 데이터의 payload를 보면 우리가 설정하지 않았던 많은 내용을 보내는 것을 확인할 수 있습니다.

이 payload를 알기 위해선 Hub라는 개념에 대해 알아야합니다.

Hub(허브)

허브란 Sentry가 호출(코드상 init)되면 생성되는 Pool입니다. 

간단하게 서비스에서 일어난 Sentry 관련 데이터들이 Pool에 들어가고 Pool에서 Sentry에 설정된 규칙에 따라 Sentry 서버로 데이터가 넘어가게 됩니다.

hub라는 개념을 조금 살펴보니 GTM의 dataLayer와 비슷한 느낌입니다.

dataLayer에 event를 push하면 gtm이 알아서 적절한 타이밍에 비동기콜을 통해 gtm서버로 데이터를 보냅니다.

이런 방식을 통해 모든 이벤트에 대한 비동기콜을 생성하지 않고 모아서 보내거니 유휴타이밍에 데이터를 보내게 됩니다. 그렇게 최적화가 가능하다는 이점이 있습니다.

요약하자면 Sentry는 아래와 같은 프로세스를 가지고 있습니다.

클라이언트에 이벤트 생성 -> Scope규칙에 따라 Hub에 적재 -> 적절한 타이밍에 Hub에 있는 데이터를 서버로 전송

configureScope (글로벌스코프)

다시 설정으로 찾아와 configureScope는 전역적인 설정을 할수 있습니다.

import * as Sentry from "@sentry/nextjs";

// set
Sentry.configureScope(function(scope) {
  scope.setTag("my-tag", "my value");
  scope.setUser({
    id: 42,
    email: "john.doe@example.com",
  });
});

// clear
Sentry.configureScope(scope => scope.clear());

기본적인 사용법은 위에 코드처럼 하면 되겠습니다.

제 상황에서는 로그인 정보를 가져오는 곳에서 Sentry 글로벌 설정을 한후에 로그인 정보가 해체되면 scope.clear를 통해 초기화해주고 있습니다.

/* 중략 */
useEffect(() => {
  if (session?.user) {
    Sentry.configureScope((scope: Sentry.Scope) => {
      scope.setUser({
        email: session.user.email,
      });
    });
  }
  return () => {
    Sentry.configureScope((scope: Sentry.Scope) => scope.clear());
  };
}, [session?.user]);
/* 중략 */

scope에서 제공해주는 메소드는 다양하게 있으니 공식문서를 조금더 읽어보시면 좋겠습니다.

withScope (로컬스코프)

withScope는 로컬 설정을 할 수 있도록 해주는 기능입니다.

특정 이벤트로그에만 추가적인 정보를 보낼때 사용할 수 있습니다.

Sentry.withScope(function(scope) {
  scope.setTag("my-tag", "my value");
  scope.setLevel("warning");
  // will be tagged with my-tag="my value"
  Sentry.captureException(new Error("my error"));
});

// will not be tagged with my-tag
Sentry.captureException(new Error("my other error"));

이런 기능을 저는 이렇게 사용하고 있습니다.

const PlayerEmptyPanel = () => {
  const { t } = useTranslation();
  const { isMobile } = useMobileDetect();
  const playerHeaderStore = usePlayerHeaderStore();

  useEffect(() => {
    Sentry.withScope(function (scope) {
      scope.setLevel("warning");
      scope.setTag("title", playerHeaderStore.title);
      Sentry.captureException(new Error("player data is Empty"));
    });
  }, []);

  return (
  );
};

그런 후에 생성된 센트리 로그를 살펴보면 아래에 title에 들어간 모습을 확인 할 수 있습니다.

Customize Tags

tag는 key-value의 문자열쌍입니다. 

import * as Sentry from "@sentry/nextjs";

Sentry.setTag("title", "워렌버핏 .....");

그런 다음 설정한 에러를 확인하면 다음처럼 title에 원하는 값이 있는 것을 확인할 수 있습니다.

주의사항 및 에러처리

유령의존성 사용하는 경우

간혹 코드 예시를 보다가 아래와 같은 import문을 가져올 때가 있습니다.

import * as Sentry from "@sentry/react";
import * as Sentry from "@Sentry/react";

별 이상없이 동작해보이지만 정확히 말하면 유령 의존성(phantom dependency)를 사용하고 있는 것입니다.

우리가 설치한 패키지는 @sentry/nextjs 입니다. 빌드하는데 이상은 없지만 로그를 보면 경고문구가 뜨기도 합니다.

There are multiple modules with names that only differ in casing.

유령 의존성에 관한 글은 이전에 작성했으니 한번 읽어보시면 좋습니다.

2022.02.16 - [개발/리액트] - [리액트] 유령 의존성부터 시작된 yarn berry 도입기

배포를 했는데 Error 나는 경우

로컬에서는 빌드도 잘 되서 merge를 하고 빌드 프로세스를 보니 다음과 같은 에러와 함께 빌드가 중단됩니다.

Sentry CLI Plugin: Command failed: /app/node_modules/@sentry/cli/sentry-cli releases new dpQDELQYsMPTgUs8B_i4A
error: API request failed
  caused by: sentry reported an error: Authentication credentials were not provided. (http status: 401)

원인을 찾아보니 자동으로 생성된 .sentryclirc파일이 빌드타임에는 없어서 발생한 문제였습니다. 

// .sentryclirc
[auth]
token=KEY
[auth]
token=KEY
[auth]
token=KEY

npx sentry 실행때 gitignore에 자동으로 sentryclirc 파일이 추가되기 때문입니다. 이것을 제거해거해주면 되겠습니다.

Console.log가 이상해요 (23.01.26 추가)

Sentry를 설치하고 해피코딩을 하고 있는데 console.log에서 instrument.js로만 출력되는 이상한 현상이 보입니다.

해결 방법은 크롬기준으로 우측상단의 톱니바퀴버튼을 클릭하여 Settings -> Ignore List에 아래 두가지를 추가하면 됩니다.

출처 : https://github.com/getsentry/sentry-react-native/issues/794#issuecomment-600232057
  • instrument.ts
  • /@sentry/
설정 화면

 

끝으로

이번 글에서는 Sentry를 도입하여 next 프로젝트에 셋팅하는 방법부터 좀더 다양한 데이터를 추가하여 확인하는 방법에 대해서 살펴보았습니다.

Sentry가 제공하는 다양한 기능이 있는 만큼 들어가셔서 확인해보고 적절한 상황에서 사용한다면 더욱 안전한 서비스를 만들 수 있을 겁니다.

끝.

 

참고자료

 

Sentry로 우아하게 프론트엔드 에러 추적하기 | 카카오페이 기술 블로그

Sentry를 통해 프론트엔드에서 발생하는 오류를 신속하게 탐지하고 정확한 원인을 파악하여 빠르게 대응하는 방법을 알아봅니다.

tech.kakaopay.com

 

 

Sentry with Next.js

Sentry is a crash reporting platform that provides you with "real-time insight into production...

dev.to

 

댓글