Next.js OpenTelemetry 가이드 정리
1. OpenTelemetry 개요
**OpenTelemetry(OTel)**은 로그/메트릭/트레이스(분산 추적)를 위한 벤더 중립(플랫폼 불문) 표준입니다.
- 특정 관측(Observability) 벤더에 종속되지 않고 계측을 구현할 수 있어, 나중에 벤더를 바꾸더라도 코드를 크게 바꾸지 않는 장점이 있습니다.
- Next.js는 기본적으로 OpenTelemetry 계측을 지원하며(Next.js 자체가 이미 계측됨),
이를 활성화하면 Next.js 내부 처리/라우트 렌더링/
fetch등에서 유용한 span을 얻을 수 있습니다.
2. Step 1: 빠른 시작 (@vercel/otel 사용)
공식 문서는 초기 구성을 쉽게 하기 위해 @vercel/otel 사용을 권장합니다.
2.1 패키지 설치
npm install @vercel/otel @opentelemetry/sdk-logs @opentelemetry/api-logs @opentelemetry/instrumentation
2.2 instrumentation.ts 파일 생성
- 프로젝트 루트에
instrumentation.ts(또는.js) 생성 src폴더 구조를 쓰면src/instrumentation.ts에 둡니다.app/또는pages/안에 두면 안 됩니다.
// instrumentation.ts
import { registerOTel } from '@vercel/otel'
export function register() {
registerOTel({ serviceName: 'next-app' })
}
Good to know:
pageExtensions로 파일 접미사를 바꾸는 설정을 쓴다면,instrumentation파일명도 그 규칙에 맞춰야 합니다.
3. Step 2: 수동(Manual) OpenTelemetry 설정 (고급)
@vercel/otel이 제공하는 옵션으로 부족한 경우, OpenTelemetry를 직접 구성할 수 있습니다.
3.1 패키지 설치
npm install @opentelemetry/sdk-node @opentelemetry/resources @opentelemetry/semantic-conventions @opentelemetry/sdk-trace-node @opentelemetry/exporter-trace-otlp-http
3.2 Edge 런타임 주의 (NodeSDK는 Edge 미지원)
NodeSDK는 Edge runtime과 호환되지 않으므로, NEXT_RUNTIME === 'nodejs'일 때만 로드해야 합니다.
// instrumentation.ts
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
await import('./instrumentation.node')
}
}
// instrumentation.node.ts
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { resourceFromAttributes } from '@opentelemetry/resources'
import { NodeSDK } from '@opentelemetry/sdk-node'
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'
import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'
const sdk = new NodeSDK({
resource: resourceFromAttributes({
[ATTR_SERVICE_NAME]: 'next-app',
}),
spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter()),
})
sdk.start()
Edge 지원이 필요하면
@vercel/otel을 사용해야 한다고 문서에서 안내합니다.
4. Step 3: 로컬에서 계측 테스트
로컬에서 트레이스를 보려면 OTel Collector + 호환 백엔드가 필요합니다.
문서는 로컬 테스트용 “OpenTelemetry dev environment” 예제를 추천합니다.
성공하면 다음을 확인할 수 있습니다.
- 루트 서버 span이
GET /requested/pathname같은 형태로 보임 - 해당 trace 아래에 다른 span들이 계층 구조로 중첩됨
더 많은 span을 보고 싶다면:
NEXT_OTEL_VERBOSE=1
5. 배포(Deployment) 옵션
5.1 Collector 사용
Collector를 사용하는 배포 환경에서는 @vercel/otel을 그대로 사용할 수 있으며, Vercel/자체 호스팅 모두 지원됩니다.
- Vercel: “Observability provider 연결”을 Vercel 문서 흐름대로 설정
- Self-hosting: 직접 Collector를 띄우고, Next.js 앱이 Collector로 telemetry를 보내도록 구성
5.2 Custom Exporter 사용
Collector 없이도, @vercel/otel 또는 manual 설정 위에 커스텀 Exporter를 붙일 수 있습니다.
6. Custom Spans 추가하기
Next.js가 기본 span을 생성해주더라도, 서비스 관점에서 의미 있는 span을 직접 추가할 수 있습니다.
6.1 패키지 설치
npm install @opentelemetry/api
6.2 커스텀 span 예시
import { trace } from '@opentelemetry/api'
export async function fetchGithubStars() {
return await trace
.getTracer('nextjs-example')
.startActiveSpan('fetchGithubStars', async (span) => {
try {
return await getValue()
} finally {
span.end()
}
})
}
register()는 환경이 새로 시작될 때 코드 실행 이전에 호출되므로, 여기서 span/설정을 초기화하면 export되는 trace에 잘 포함됩니다.
7. Next.js의 Default Spans 요약
Next.js는 여러 “기본 span”을 자동 생성합니다.
span attributes는 OpenTelemetry semantic conventions를 따르며, Next.js는 next.* 네임스페이스의 커스텀 속성도 제공합니다.
7.1 Next.js 커스텀 attributes(대표)
next.span_name: span 이름(중복 정보)next.span_type: span 타입 식별자next.route: 라우트 패턴 (예:/[param]/user)next.rsc: RSC 요청 여부 (prefetch 등)next.page: App Router 내부 식별 값(파일 단위에 가까움)next.segment: 레이아웃/페이지 모듈 로딩 관련 식별
7.2 기본 span 종류(대표)
[http.method] [next.route](root request span)render route (app) [next.route]fetch [http.method] [http.url]executing api route (app) [next.route]getServerSideProps [next.route]getStaticProps [next.route]render route (pages) [next.route]generateMetadata [next.page]resolve page componentsresolve segment modulesstart response(첫 바이트 전송 시점, zero-length span)
7.3 fetch span 끄기
기본 fetch 계측 대신 커스텀 fetch 계측을 쓰고 싶다면 다음 환경 변수를 사용할 수 있습니다.
NEXT_OTEL_FETCH_DISABLED=1