Turborepo 같은 모노레포 환경에서 Sentry를 세팅하려고 하면 생각보다 머리가 아픕니다.
하지만 저는 기존에 세팅해둔 Shared Package 전략이 있어 한번 세팅을 해보려합니다. (이전 게시글 참고)
sentry 공식 홈페이지에서도 모노레포를 위한 문서가 딱히 없어 걱정반 설렘 반으로 작업을 시작했네요.
그 과정 바로 공유해 드릴게요.
Shared Package 전략글에 상세히 설명되어 있어 간단히 짚고만 가겠습니다.
보통은 npx @sentry/wizard를 각 앱에서 돌리지만, 모노레포에선 이게 기술 부채가 됩니다.
beforeSend 로직이나 에러 마스킹 수정을 모든 앱에서 반복해야 합니다..env를 뒤져야 하죠.우리는 @repo/sentry라는 이름의 독립된 공간에서 이 모든 걸 관리할 겁니다.
packages/sentry에 자리를 잡고, 모든 앱이 가져다 쓸 수 있는 "Sentry 컨트롤 타워"를 만듭니다.
index.ts)단순히 초기화만 하는 게 아니라, 서버/클라이언트/엣지 환경에 맞춰 최적화된 초기화 함수를 정의합니다.
센트리 옵션은 공식문서, 블로그 등 많은 곳에세 이미 정리되어 있기에 index.ts에 어떻게 합쳤는지만 보여드리겠습니다.
import * as Sentry from "@sentry/nextjs";
// 중앙에서 관리하는 DSN
const SENTRY_DSN = 'https://...';
export const initSentryClient = () => {
Sentry.init({
dsn: SENTRY_DSN,
tracesSampleRate: 1.0,
integrations: [Sentry.consoleLoggingIntegration({ levels: ["log", "warn", "error"] })],
enableLogs: true,
});
};
export const initSentryServer = () => {
Sentry.init({
dsn: SENTRY_DSN,
tracesSampleRate: 1.0,
});
};
// ...Edge 로직도 동일하게
next.config.js 옵션 공통화빌드 시 소스맵 업로드나 터널링(광고 차단 우회) 설정도 패키지에서 미리 정의해 둡니다.
export const sentryConfigOptions = {
org: "조직명",
project: "프로젝트명",
silent: !process.env.CI,
tunnelRoute: "/monitoring",
};
현재 저는 Next.js 15+ 버전을 사용중이기에 최신 규격에 맞게 instrumentation.ts를 활용했습니다.
instrumentation 훅은 아래와 같으니 참고해보세요.
instrumentation.ts (Server)
import * as Sentry from '@repo/sentry';
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
const { initSentryServer } = await import('@repo/sentry');
initSentryServer();
}
}
export const onRequestError = Sentry.captureRequestError;
instrumentation-client.ts (Client)
import * as Sentry from '@repo/sentry';
Sentry.initSentryClient();
export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;
요번 작업에서 제 스스로 잘 도입했다 싶은 기능들을 아래에 정리하였으니 참고해보세요.
Sentry는 단순히 에러를 쌓아두는 창고가 아닙니다. 잘 세팅된 Sentry는 개발자가 잠든 사이에도 서비스의 건강도를 체크해 주는 소중한 동료가 되죠.
오늘 정리해 드린 모노레포 Sentry 설정으로 여러분의 DX를 한 단계 높여보세요!