콘텐츠로 이동

트레이싱 설정 | Next.js용 Sentry

소스 URL: https://docs.sentry.io/platforms/javascript/guides/nextjs/tracing

트레이싱은 Next.js 애플리케이션을 통과하는 요청의 타이밍과 흐름을 캡처합니다. tracing과 Sentry가 서비스 전반의 성능을 추적하기 위해 트레이스를 사용하는 방법을 자세히 알아보세요.

Sentry는 대부분의 작업을 자동으로 계측하지만, Server Action은 수동 설정이 필요합니다.

트레이싱을 활성화하기 전에 다음을 확인하세요.

  • Next.js 애플리케이션에 Sentry SDK 설치
  • 세 가지 설정 파일(instrumentation-client.ts, sentry.server.config.ts, sentry.edge.config.ts) 모두에서 Sentry 초기화

세 가지 런타임 파일 모두의 Sentry 설정에 tracesSampleRate를 추가하세요.

개발 환경에서는 100%, 운영 환경에서는 10-20%로 시작하세요. 트래픽 규모와 예산에 맞춰 조정하세요.

instrumentation-client.ts

import * as Sentry from "@sentry/nextjs";
Sentry.init({
dsn: "___PUBLIC_DSN___",
tracesSampleRate: process.env.NODE_ENV === "development" ? 1.0 : 0.1,
});

SDK는 코드가 실행되는 위치에 따라 서로 다른 작업을 계측합니다.

Runtime자동 계측 항목
Client페이지 로드, 내비게이션, fetch 요청, Web Vitals
ServerAPI 라우트, Server Components, getServerSideProps
EdgeMiddleware, edge API 라우트
// All of these create spans automatically
// Client: navigation creates a span
<Link href="/dashboard">Dashboard</Link>;
// Server: API route creates a span
export async function GET() {
return Response.json({ data });
}
// Server Component: creates a span
export default async function Page() {
const data = await fetchData();
return <div>{data}</div>;
}

타임아웃, INP 설정, span 필터링 같은 구성 옵션은 Automatic Instrumentation을 참고하세요.

Server Action은 자동으로 계측되지 않습니다. 래핑하지 않으면 타이밍이나 컨텍스트 없이 익명 서버 작업으로 표시됩니다.

withServerActionInstrumentation을 사용하면 다음이 가능합니다.

  • 각 액션에 대해 이름 있는 span 생성
  • 타이밍 및 오류 캡처
  • headers를 통해 클라이언트와 서버 트레이스 연결
  • formData를 통해 Sentry 이벤트에 폼 데이터 첨부

app/actions.ts

"use server";
import * as Sentry from "@sentry/nextjs";
export async function createOrder(formData: FormData) {
return Sentry.withServerActionInstrumentation(
"createOrder",
async () => {
// Your action logic
const order = await db.orders.create({
data: { items: formData.get("items") },
});
return { success: true, orderId: order.id };
},
);
}

headers를 전달해 클라이언트 측 트레이스와 서버 측 span을 연결하면 브라우저-서버 경계를 넘는 전체 분산 트레이싱이 가능합니다. formData를 전달하면 제출된 폼 데이터를 Sentry 이벤트에 첨부해 디버깅을 더 쉽게 할 수 있습니다.

app/actions.ts

"use server";
import * as Sentry from "@sentry/nextjs";
import { headers } from "next/headers";
export async function submitForm(formData: FormData) {
return Sentry.withServerActionInstrumentation(
"submitForm",
{
headers: await headers(), // Connect client and server traces
formData, // Attach form data to events
recordResponse: true, // Include response data
},
async () => {
// Action logic with full trace context
},
);
}

SDK는 모든 페이지 로드에서 Web Vitals를 자동으로 캡처합니다. 이 지표는 실제 사용자 경험을 측정합니다.

Metric측정 대상기준값(좋음)
LCPLargest Contentful Paint — 로딩 성능≤ 2.5s
INPInteraction to Next Paint — 반응성≤ 200ms
CLSCumulative Layout Shift — 시각적 안정성≤ 0.1
FCPFirst Contentful Paint — 초기 렌더링≤ 1s
TTFBTime to First Byte — 서버 응답≤ 100ms

Web Vitals는 페이지 로드 트랜잭션의 measurement로 표시되며 Performance Score에 반영됩니다. 각 지표에 대한 자세한 설명은 Web Vitals Concepts를 참고하세요.

다음을 측정하고 싶다면 커스텀 span을 추가하세요.

  • 비즈니스 작업(체크아웃 플로우, 다단계 위저드)
  • 별도로 추적하려는 외부 API 호출
  • 자동 캡처되지 않는 데이터베이스 작업
  • 비용이 큰 계산 작업

startSpanManual, startInactiveSpan을 포함한 전체 span API는 Custom Instrumentation을 참고하세요.

app/api/checkout/route.ts

import * as Sentry from "@sentry/nextjs";
export async function POST(request: Request) {
return Sentry.startSpan(
{ name: "checkout.process", op: "checkout" },
async () => {
// Nested spans for sub-operations
const cart = await Sentry.startSpan(
{ name: "checkout.validate_cart", op: "validation" },
() => validateCart(request),
);
const payment = await Sentry.startSpan(
{ name: "checkout.process_payment", op: "payment" },
() => processPayment(cart),
);
return Response.json({ orderId: payment.orderId });
},
);
}

Sentry에서 필터링과 디버깅을 위해 span에 데이터를 첨부하세요.

Sentry.startSpan(
{
name: "order.process",
op: "order",
attributes: {
"order.id": orderId,
"order.value": cart.total,
"order.item_count": cart.items.length,
},
},
async () => {
// Operation logic
},
);

SDK는 다음에 대해 트레이스 컨텍스트를 자동 전파합니다.

  • 자체 도메인으로의 fetch() 요청
  • Server Actions(withServerActionInstrumentation을 headers와 함께 사용할 때)

외부 API의 경우 tracePropagationTargets를 구성하세요.

instrumentation-client.ts

Sentry.init({
dsn: "___PUBLIC_DSN___",
tracesSampleRate: 0.1,
// Propagate traces to these external services
tracePropagationTargets: [
"localhost",
/^https:\/\/api\.yourcompany\.com/,
/^https:\/\/payments\.stripe\.com/,
],
});

CORS 구성 및 수동 트레이스 전파(WebSockets 등)는 Distributed Tracing을 참고하세요.

시나리오자동 계측 여부조치
페이지 로드 및 내비게이션Yes없음
API 라우트 (route.ts)Yes없음
Server ComponentsYes없음
getServerSidePropsYes없음
Server ActionsNowithServerActionInstrumentation 사용
외부 API 호출PartialtracePropagationTargets 구성
커스텀 비즈니스 로직NostartSpan 사용

트레이스를 너무 많이 전송하고 있다면 샘플링 비율을 낮추거나, 라우트 기반 동적 샘플링을 위해 tracesSampler를 사용하세요.

더 많은 옵션은 Configure Sampling을 참고하세요.

Sentry.init({
tracesSampler: ({ name }) => {
// Sample 5% of health checks
if (name.includes("health")) return 0.05;
// Sample 50% of API routes
if (name.includes("/api/")) return 0.5;
// Default 10%
return 0.1;
},
});