Next.js Instrumentation ์ ๋ฆฌ
๐ Instrumentation์ด๋?
Instrumentation์ Next.js 13.2๋ถํฐ ๋์ ๋ ๊ธฐ๋ฅ์ผ๋ก, ์ฑ์ด ์์๋ ๋ ๋ฑ ํ ๋ฒ ์คํ๋๋ ์ด๊ธฐํ ์ฝ๋๋ฅผ ์ํ ํน๋ณํ ํ์ผ์ ๋๋ค.
// app/instrumentation.ts ๋๋ src/instrumentation.ts
export async function register() {
// ์๋ฒ๊ฐ ๋ถํ
๋ ๋ ์คํ๋๋ ์ฝ๋
console.log('Next.js ์ฑ์ด ์์๋ฉ๋๋ค!');
}
๐ฏ ์ฃผ์ ํน์ง
- ์คํ ์์
- ์๋ฒ๊ฐ ์ฒ์ ์์๋ ๋
- Cold start ์ (์๋ฒ๋ฆฌ์ค ํ๊ฒฝ)
- ๋ชจ๋ ํ๊ฒฝ(Node.js, Edge, Client)์์ ๊ฐ๊ฐ ํ ๋ฒ์ฉ
- ์คํ ํ๊ฒฝ ๊ตฌ๋ถ
// instrumentation.ts - ์๋ฒ์ฉ
// instrumentation-client.ts - ๋ธ๋ผ์ฐ์ ์ฉ (๋ณ๋ ํ์ผ!)
export async function register() {
// ์๋ฒ ์ฌ์ด๋ (Node.js)
if (process.env.NEXT_RUNTIME === 'nodejs') {
console.log('Node.js ์๋ฒ ์์!');
}
// Edge Runtime (Middleware, Edge API)
if (process.env.NEXT_RUNTIME === 'edge') {
console.log('Edge Runtime ์์!');
}
}
๐ก ํ์ฉ ์ฌ๋ก
1. ๋ชจ๋ํฐ๋ง ๋๊ตฌ ์ด๊ธฐํ (๊ฐ์ฅ ์ผ๋ฐ์ )
// instrumentation.ts
import * as Sentry from '@sentry/nextjs';
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
Sentry.init({
dsn: process.env.SENTRY_DSN,
// Node.js ํนํ ์ค์
});
}
}
2. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ํ ์ค์
import { PrismaClient } from '@prisma/client';
let prisma: PrismaClient;
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
// ๊ธ๋ก๋ฒ Prisma ์ธ์คํด์ค ์์ฑ
globalThis.prisma = new PrismaClient();
await globalThis.prisma.$connect();
console.log('DB ์ฐ๊ฒฐ ์๋ฃ');
}
}
3. OpenTelemetry ์ค์
import { NodeSDK } from '@opentelemetry/sdk-node';
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
const sdk = new NodeSDK({
serviceName: 'my-nextjs-app',
// ํธ๋ ์ด์ฑ ์ค์
});
sdk.start();
}
}
4. ํ๊ฒฝ ๋ณ์ ๊ฒ์ฆ
export async function register() {
const requiredEnvVars = [
'DATABASE_URL',
'API_SECRET_KEY',
'REDIS_URL'
];
for (const envVar of requiredEnvVars) {
if (!process.env[envVar]) {
throw new Error(`ํ์ ํ๊ฒฝ ๋ณ์ ๋๋ฝ: ${envVar}`);
}
}
console.log('โ
ํ๊ฒฝ ๋ณ์ ๊ฒ์ฆ ์๋ฃ');
}
โ๏ธ ์ค์ ๋ฐฉ๋ฒ
- next.config.js์์ ํ์ฑํ
// next.config.js
module.exports = {
experimental: {
instrumentationHook: true, // ํ์ฑํ!
},
};
- ํ์ผ ์์ฑ ์์น
ํ๋ก์ ํธ/
โโโ app/
โ โโโ instrumentation.ts // App Router
โโโ src/
โ โโโ instrumentation.ts // ์๋ฒ/Edge
โ โโโ instrumentation-client.ts // ํด๋ผ์ด์ธํธ
โโโ instrumentation.ts // Pages Router
๐ ์ผ๋ฐ ์ด๊ธฐํ์์ ์ฐจ์ด
โ ๊ธฐ์กด ๋ฐฉ๋ฒ์ ๋ฌธ์ ์
// app/layout.tsx
import { initSentry } from './sentry';
// ๋ฌธ์ : ๋ชจ๋ ์์ฒญ๋ง๋ค ์คํ๋จ!
initSentry();
export default function RootLayout() {
// ...
}
โ Instrumentation ์ฅ์
// instrumentation.ts
export async function register() {
// ์๋ฒ ์๋ช
์ฃผ๊ธฐ๋น ํ ๋ฒ๋ง ์คํ!
await initSentry();
await connectDatabase();
await warmupCache();
}
๐ ์คํ ํ๋ฆ ๋ค์ด์ด๊ทธ๋จ
์๋ฒ ์์
↓
instrumentation.ts register() ์คํ
↓
๋ฐํ์ ์ฒดํฌ (nodejs/edge)
↓
ํด๋น ํ๊ฒฝ ์ด๊ธฐํ ์ฝ๋ ์คํ
↓
์๋ฒ ์ค๋น ์๋ฃ
↓
์์ฒญ ์ฒ๋ฆฌ ์์
๋ธ๋ผ์ฐ์ ๋ก๋
↓
instrumentation-client.ts ์คํ
↓
ํด๋ผ์ด์ธํธ ์ด๊ธฐํ
๐ ์ค์ ํ
- ๋ฌด๊ฑฐ์ด ์์ ์ ๋น๋๊ธฐ๋ก
export async function register() {
// ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ก ๋ถํ
์๊ฐ ๋จ์ถ
await Promise.all([
initDatabase(),
initCache(),
initMonitoring(),
]);
}
- ์๋ฌ ์ฒ๋ฆฌ ํ์
export async function register() {
try {
await riskyInitialization();
} catch (error) {
console.error('์ด๊ธฐํ ์คํจ:', error);
// ์ฑ์ด ์์๋์ง ์๋๋ก ํ ์๋ ์์
process.exit(1);
}
}
- ๊ฐ๋ฐ/ํ๋ก๋์ ๋ถ๊ธฐ
export async function register() {
if (process.env.NODE_ENV === 'development') {
// ๊ฐ๋ฐ ์ ์ฉ ๋๊ตฌ
const { setupDevTools } = await import('./dev-tools');
setupDevTools();
}
}'TIL' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [251123 TIL] Turbopack ๊ฐ์ ์์กด์ฑ ๊ฒฝ๊ณ ์ํฉ (0) | 2025.11.23 |
|---|---|
| [251123 TIL] OpenTelemetry? (with Next.js) (0) | 2025.11.23 |
| [251102 TIL] PostgREST vs GraphQL(Hasura)๊ธฐ์ ์คํ ๋น๊ต (0) | 2025.11.02 |
| [251031 TIL] naver ๋ก๊ทธ์ธ ๊ตฌํ with Supabase 3ํธ (1) | 2025.10.31 |
| [251029 TIL] Cookie, CORS, Site, Origin ์ด์ ๋ฆฌ (0) | 2025.10.29 |