Observability는 Next.js 앱의 동작과 성능을 이해하고 최적화하는 데 매우 중요하다. 애플리케이션이 더욱 복잡해짐에 따라 발생할 수 있는 문제를 식별하고 진단하는 것이 점점 어려워진다. 로깅 및 메트릭과 같은 Observability 도구를 활용하여 개발자는 애플리케이션 동작에 대한 통찰력을 얻고 최적화 영역을 식별할 수 있다. Observability를 통해 개발자는 문제가 심각해지기 전에 문제를 사전에 해결하고 더 나은 사용자 경험을 제공할 수 있다. 따라서 성능을 개선하고 리소스를 최적화하며 사용자 경험을 향상시키기 위해 Next.js 애플리케이션에서 observability를 사용하는 것이 좋다.
앱 계측에 OpenTelemetry를 사용하는 것이 좋다. 코드를 변경하지 않고 observability를 변경할 수 있도록 하는 앱을 계측하는 플랫폼에 구애받지 않는 방법이다.
Next.js는 즉시 사용 가능한 OpenTelemetry 계측을 지원한다. 이는 이미 Next.js 자체를 계측했음을 의미한다. OpenTelemetry를 활성화하면 getStaticProps와 같은 모든 코드를 유용한 속성으로 스팬에 자동으로 래핑 된다.
현재 서버리스 기능에서만 OpenTelemetry 바인딩을 지원한다. Edge 또는 클라이언트 측 코드를 제공하진 않는다.
- 시작하기
OpenTelemetry는 확장 가능하지만 올바르게 설정하는 것은 매우 장황할 수 있다. 그래서 빠르게 시작하는 데 도움이 되는 @vercel/otel 패키지를 준비한다. 확장할 수 없으며 설정을 사용자 지정해야 하는 경우에는 OpenTelemetry를 수동으로 구성해야 한다.
@vercel/otel 사용하기
시작하려면 @vercel/otel을 설치해야 한다.
npm install @vercel/otel
다음으로 프로젝트의 루트 디렉토리에 사용자 지정 instrumentation.ts(또는 .js) 파일을 만든다.
// project/instrumentation.ts
import { registerOTel } from '@vercel/otel'
export function register() {
registerOTel('next-app')
}
계측 파일은 앱 또는 페이지 디렉토리가 아니라 프로젝트의 루트에 있어야 한다. pagesExtension 구성 옵션을 사용하여 접미사를 추가하는 경우 계층 파일 이름도 일치하도록 업데이트해야 한다.
수동으로 OpenTelemetry 구성하기
래퍼 @vercel/otel이 필요에 맞지 않으면 OpenTelemetry를 수동으로 구성할 수 있다. 먼저 OpenTelemetry 패키지를 설치해야 한다.
npm install @opentelemetry/sdk-node @opentelemetry/resources @opentelemetry/semantic-conventions @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-http
이제 instrumentation.ts에서 NodeSDK를 초기화할 수 있다. OpenTelemetry API는 Edge 런타임과 호환되지 않으므로 process.env.NEXT_RUNTIME === 'nodejs'인 경우에만 가져오는지 확인해야 한다. 노드를 사용할 때만 조건부를 가져오는 새 파일 instrumentation.node.ts를 생성하는 것이 좋다.
// instrumentation.ts
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
await import('./instrumentation.node.ts')
}
}
// instrumentation.node.ts
import { trace, context } from '@opentelemetry/api'
import { NodeSDK } from '@opentelemetry/sdk-node'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { Resource } from '@opentelemetry/resources'
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node'
const sdk = new NodeSDK({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: 'next-app',
}),
spanProcessor: new SimpleSpanProcessor(new OTLPTraceExporter()),
})
sdk.start()
이렇게 하면 @vercel/otel을 사용하는 것과 동일하지만 수정 및 확장이 가능하다. 예를 들어 @opentelemetry/exporter-trace-otlp-http 대신 @opentelemetry/exporter-trace-otlp-grpc를 사용하거나 더 많은 리소스 속성을 지정할 수 있다.
- instumentation 테스트하기
OpenTelemetry 추적을 로컬에서 테스트하려면 호환되는 백엔드가 있는 OpenTelemetry 수집기가 필요하다. OpenTelemetry 개발 환경을 사용하는 것이 좋다.
모든 것이 제대로 작동하면 GET /requested/pathname 레이블이 지정된 루트 서버 범위를 볼 수 있어야 한다. 해당 특정 추적의 다른 모든 범위는 그 아래에 중첩된다.
Next.js는 기본적으로 내보낸 것보다 더 많은 스팬을 추적한다. 더 많은 스팬을 보려면 NEXT_OTEL_VERBOSE=1로 설정해야 한다.
- Deployment
OpenTelemetry Collector 사용하기
OpenTelemetry Collector로 배포하는 경우 @vercel/otel을 사용할 수 있다. Vercel과 자체 호스팅 시 모두 작동한다.
Custom Exporters
OpenTelemetry Collector를 사용하는 것이 좋다. 플랫폼에서 이것이 가능하지 않은 경우 수동 OpenTelemetry 구성과 함께 사용자 정의 OpenTelemetry 내보내기를 사용할 수 있다.
- Custom Spans
OpenTelemetry API를 사용하여 사용자 지정 범위를 추가할 수 있다.
npm install @opentelemetry/api
다음 예제는 GitHub 별을 가져오고 사용자 지정 fetchGithubStarts 범위를 추가하여 가져오기 요청의 결과를 추적하는 함수를 보여준다.
import { trace } from '@opentelemetry/api'
export async function fetchGithubStarts() {
return await trace
.getTracer('nextjs-example')
.startActiveSpan('fetchGitHubStars', async (span) => {
try {
return await getValue()
} finally {
span.end()
}
})
}
등록 기능은 코드가 새 환경에서 실행되기 전에 실행된다. 새 스팬 만들기를 시작할 수 있으며 내보낸 추적에 올바르게 추가되어야 한다.
- Default Spans in Next.js
Next.js는 애플리케이션 성능에 대한 유용한 통찰력을 제공하기 위해 여러 범위를 자동으로 계측한다. 범위의 특성은 OpenTelemetry 의미 체계 규칙을 따른다. 또한 다음 네임스페이스 아래에 몇 가지 사용자 정의 속성을 추가한다.
next.span_name | 중복 스팬 이름 |
next.span_type | 각 범위 유형에는 고유한 식별자를 가짐 |
next.router | 요청의 경로 패턴(예: /[param]/user) |
next.page | 앱 라우터에서 사용하는 내부 값이다. 특정 파일(예: page.ts, layout.ts, loading.ts 및 기타)에 대한 경로로 생각할 수 있다. /layout은 /(groupA)/layout.ts와 /(groupB)/layout.ts를 모두 식별하는 데 사용할 수 있으므로 next.route와 쌍을 이룰 때만 고유 식별자로 사용할 수 있다. |
[http.method] [next.route]
- next.span_type: BaseServer.handleRequest
이 span은 Next.js 애플리케이션에 대한 각 수신 요청의 루트 스팬을 나타낸다. 요청의 HTTP 메서드, 경로, 대상 및 상태 코드를 추적한다.
Common HTTP attributes | Server HTTP attributes |
https.method | http.route |
http.status_code | http.target |
next.span_name |
next.span_type |
next.route |
render route (app) [next.route]
- next.span_type: AppRender.getBodyResult
이 span은 앱 라우터에서 경로를 렌더링 하는 프로세스를 나타낸다.
next.span_name |
next.span_type |
next.route |
fetch [http.method] [http.url]
- next.span_type: AppRender.fetch
이 span은 코드에서 실행된 가져오기 요청을 나타낸다.
Common HTTP attributes | Client HTTP attributes |
https.method | http.url |
net.peer.name | |
net.peer.port (only if specified) |
next.span_name |
next.span_type |
excuting api route (app) [next.route]
- next.span_type: AppRouteHAndlers.runHandler
이 span은 앱 라우터에서 API 경로 핸들러의 실행을 나타낸다.
next.span_name |
next.span_type |
next.route |
getServerSideProps [next.route]
- next.span_type: Render.getServerSideProps
이 span은 특정 경로에 대한 getServerSideProps의 실행을 나타낸다.
next.span_name |
next.span_type |
next.route |
getStaticProps [next.route]
- next.span_type: Render.renderDocument
이 span은 특정 경로에 대한 getStaticProps 실행을 나타낸다.
next.span_name |
next.span_type |
next.route |
render route (pages) [next.route]
- next.span_type: Render.renderDocument
이 span은 특정 경로에 대한 문서를 렌더링 하는 프로세스를 나타낸다.
next.span_name |
next.span_type |
next.route |
generateMetadata [next.page]
- next.span_type: ResolveMetadata.generateMetadata
이 span은 특정 페이지에 대한 메타데이터를 생성하는 프로세스를 나타낸다(단일 경로에 이러한 범위가 여러 개 있을 수 있음).
next.span_name |
next.span_type |
next.route |
'Next.js' 카테고리의 다른 글
Next.js 12-2 Configuring ESLint (0) | 2023.06.22 |
---|---|
Next.js 12-1 Configuring TypeScript (0) | 2023.06.19 |
Next.js 9-7 Lazy Loading (0) | 2023.06.15 |
Next.js 9-6 Static Assets (0) | 2023.06.14 |
Next.js 9-5 Metadata (1) | 2023.06.13 |