Prometheus ๋ฉํธ๋ฆญ ์์ง ๋ฐ ๋ด๋ณด๋ด๊ธฐ๋ฅผ ์ํ TypeScript ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ชจ์์ ๋๋ค. PM2 ํด๋ฌ์คํฐ๋ง ํ๊ฒฝ์์์ ๋ฉํธ๋ฆญ ์์ง์ ์ง์ํ๋ฉฐ, Koa, Hono ๋ฐ Next.js ํ๋ ์์ํฌ์์ ํตํฉ์ ์ ๊ณตํฉ๋๋ค.
์ด ๋ชจ๋ ธ๋ ํฌ๋ ๋ค์๊ณผ ๊ฐ์ ํจํค์ง๋ค๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค:
ํต์ฌ Prometheus ์ ํธ๋ฆฌํฐ ๋ฐ PM2 ํตํฉ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ๊ธฐ๋ณธ ํจํค์ง์ ๋๋ค.
์ฃผ์ ๊ธฐ๋ฅ:
- Prometheus ํ์คํ ๊ทธ๋จ ๋ฐ ๊ฒ์ด์ง ๋ฉํธ๋ฆญ ๋ฑ๋ก
- PM2 ํ๋ก์ธ์ค ๊ฐ ๋ฉํธ๋ฆญ ์์ง ๋ฐ ์ง๊ณ
- Next.js ๋ผ์ฐํธ ์ ๊ทํ
- HTTP ์ํ ์ฝ๋ ๊ทธ๋ฃนํ
- ๊ธฐ๋ณธ Node.js ๋ฉํธ๋ฆญ ์์ง (๊ธฐ๋ณธ๊ฐ: true)
Koa.js ํ๋ ์์ํฌ์ฉ Prometheus ๋ฏธ๋ค์จ์ด ๋ฐ ๋ผ์ฐํฐ๋ฅผ ์ ๊ณตํฉ๋๋ค.
์ฃผ์ ๊ธฐ๋ฅ:
- HTTP ์์ฒญ ๋ฉํธ๋ฆญ ์์ง ๋ฏธ๋ค์จ์ด
- ๋ฉํธ๋ฆญ ์๋ํฌ์ธํธ ๋ผ์ฐํฐ
- API ํธ๋ ์ด์ฑ ๋ฏธ๋ค์จ์ด
- ์์ฒญ ๊ฒฝ๋ก ์ ๊ทํ ์ง์
Hono ํ๋ ์์ํฌ์ฉ Prometheus ๋ฏธ๋ค์จ์ด ๋ฐ ๋ผ์ฐํฐ๋ฅผ ์ ๊ณตํฉ๋๋ค.
์ฃผ์ ๊ธฐ๋ฅ:
- HTTP ์์ฒญ ๋ฉํธ๋ฆญ ์์ง ๋ฏธ๋ค์จ์ด
- ๋ฉํธ๋ฆญ ์๋ํฌ์ธํธ ๋ผ์ฐํฐ
- API ํธ๋ ์ด์ฑ ๋ฏธ๋ค์จ์ด
- ์์ฒญ ๊ฒฝ๋ก ์ ๊ทํ ์ง์
Next.js ์ ํ๋ฆฌ์ผ์ด์ ์ฉ ํตํฉ ์๋ฒ ์๋ฃจ์ ์ ์ ๊ณตํฉ๋๋ค.
์ฃผ์ ๊ธฐ๋ฅ:
- ๋ฉํธ๋ฆญ ์์ง์ด ํตํฉ๋ Next.js ์๋ฒ
- ์๋ ๋ผ์ฐํธ ํจํด ๋งค์นญ
- PM2 ํด๋ฌ์คํฐ ํ๊ฒฝ ์ง์
๊ฐ ํจํค์ง๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ์ค์นํ ์ ์์ต๋๋ค:
# ์ฝ์ด ํจํค์ง
npm install @naverpay/prometheus-core
# Koa ์ฌ์ฉ ์
npm install @naverpay/prometheus-koa
# Hono ์ฌ์ฉ ์
npm install @naverpay/prometheus-hono
# Next.js ์ฌ์ฉ ์
npm install @naverpay/prometheus-nextimport Koa from 'koa'
import { createKoaPrometheusExporter } from '@naverpay/prometheus-koa'
const app = new Koa()
const { middleware, router } = await createKoaPrometheusExporter({
pm2: true, // PM2 ํ๊ฒฝ์์ ์คํ ์
metricsPath: '/metrics',
collectDefaultMetrics: true,
})
app.use(middleware)
app.use(router.routes())
app.listen(3000)import { createNextServerWithMetrics } from '@naverpay/prometheus-next'
const server = await createNextServerWithMetrics({
pm2: true,
nextOptions: { dev: false },
metricsPath: '/metrics',
})
server.listen(3000)๊ฐ ํจํค์ง๋ ๋ค์๊ณผ ๊ฐ์ ๋ฉํธ๋ฆญ์ ์์งํฉ๋๋ค:
- ๋ฉํธ๋ฆญ๋ช
:
http_request_duration_seconds - ํ์ : Histogram
- ๋ผ๋ฒจ:
status_code,method,path
- ๋ฉํธ๋ฆญ๋ช
:
http_api_request_duration_seconds - ํ์ : Histogram
- ๋ผ๋ฒจ:
path,status,method
- ๋ฉํธ๋ฆญ๋ช
:
up - ํ์ : Gauge
- ์ค๋ช : ์๋น์ค ๊ฐ์ฉ์ฑ (1 = ์คํ ์ค, 0 = ์ค๋จ)
- CPU ์ฌ์ฉ๋ฅ
- ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋
- ์ด๋ฒคํธ ๋ฃจํ ์ง์ฐ
- HTTP ์์ฒญ ์ง์์๊ฐ
- ๊ฐ๋น์ง ์ปฌ๋ ์ ํต๊ณ
์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ PM2 ํด๋ฌ์คํฐ ํ๊ฒฝ์์ ์ฌ๋ฌ ํ๋ก์ธ์ค์ ๋ฉํธ๋ฆญ์ ์๋์ผ๋ก ์ง๊ณํฉ๋๋ค:
- ๊ฐ ์์ปค ํ๋ก์ธ์ค๊ฐ ์์ฒด ๋ฉํธ๋ฆญ์ ์์ง
- ๋ฉํธ๋ฆญ ์๋ํฌ์ธํธ ์์ฒญ ์ ๋ชจ๋ ํ๋ก์ธ์ค์ ๋ฉํธ๋ฆญ์ ์์ง
- Prometheus ํ์ค์ ๋ฐ๋ผ ๋ฉํธ๋ฆญ์ ์ง๊ณํ์ฌ ๋ฐํ
ํน์ ์์ฒญ์ ๋ฉํธ๋ฆญ ์์ง์์ ์ ์ธํ ์ ์์ต๋๋ค:
const { middleware } = await createKoaPrometheusExporter({
pm2: true,
bypass: (context) => {
// ํฌ์ค์ฒดํฌ ์์ฒญ ์ ์ธ
return context.path === '/health'
}
})๋์ ๋ผ์ฐํธ๋ฅผ ๊ทธ๋ฃนํํ์ฌ ๋ฉํธ๋ฆญ์ ์์งํ ์ ์์ต๋๋ค:
const { middleware } = await createKoaPrometheusExporter({
pm2: true,
normalizePath: (context) => {
// /user/123 -> /user/:id
return context.path.replace(/\/\d+/g, '/:id')
}
})์ํ ์ฝ๋๋ฅผ ์ปค์คํ ํ์์ผ๋ก ๊ทธ๋ฃนํํ ์ ์์ต๋๋ค:
const { middleware } = await createKoaPrometheusExporter({
pm2: true,
formatStatusCode: (context) => {
if (context.status >= 400) return 'error'
if (context.status >= 300) return 'redirect'
return 'success'
}
})์ด ํ๋ก์ ํธ๋ MIT ๋ผ์ด์ผ์ค ํ์ ๋ฐฐํฌ๋ฉ๋๋ค.
๋ฒ๊ทธ ๋ฆฌํฌํธ, ๊ธฐ๋ฅ ์์ฒญ, ํ ๋ฆฌํ์คํธ๋ฅผ ํ์ํฉ๋๋ค.
๋ฌธ์์ฌํญ์ด๋ ์ง์์ด ํ์ํ ๊ฒฝ์ฐ ์ด์๋ฅผ ์์ฑํด ์ฃผ์ธ์.
> pnpm turbo gen init
? What is the name of the package? (You can skip the `@naverpay/` prefix) random
? Enter a space separated list of dependencies you would like to install react
Scope: all 4 workspace projects
Packages: +1
+
Progress: resolved 679, reused 665, downloaded 0, added 0, done
โญ Warning โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ โ
โ Ignored build scripts: core-js-pure. โ
โ Run "pnpm approve-builds" to pick which dependencies should be allowed to run โ
โ scripts. โ
โ โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
Done in 950ms using pnpm v10.13.1
>>> Changes made:
โข Config sanitized (function)
โข /packages/random/package.json (add)
โข /packages/random/tsconfig.json (add)
โข /packages/random/src/index.ts (add)
โข /packages/random/package.json (modify)
โข Package scaffolded (function)
๋ค์ํ ์์ ์ ์ํ ์ฌ์ ์ ์๋ ์คํฌ๋ฆฝํธ๊ฐ ํฌํจ๋์ด ์์ต๋๋ค:
| ์คํฌ๋ฆฝํธ | ์ค๋ช |
|---|---|
pnpm start |
๋ชจ๋ ํจํค์ง์์ ์์ ์คํฌ๋ฆฝํธ๋ฅผ ์คํ. |
pnpm build |
Monorepo์ ๋ชจ๋ ํจํค์ง๋ฅผ ๋น๋. |
pnpm test |
๋ชจ๋ ํจํค์ง์์ ํ ์คํธ ์คํ. |
pnpm lint |
ESLint๋ก ์ฝ๋ ๋ฆฐํธ. |
pnpm lint:fix |
๋ฆฐํธ ๋ฌธ์ ๋ฅผ ์๋์ผ๋ก ์์ . |
pnpm prettier |
Prettier๋ก ํฌ๋งท ํ์ธ. |
pnpm prettier:fix |
Prettier๋ก ์ฝ๋ ํฌ๋งท ์๋ ์์ . |
pnpm markdownlint |
Markdown ํ์ผ ๋ฆฐํธ ์คํ. |
pnpm markdownlint:fix |
Markdown ๋ฆฐํธ ๋ฌธ์ ์๋ ์์ . |
pnpm clean |
์์ ๊ณต๊ฐ ์ด๊ธฐํ ๋ฐ ์์กด์ฑ ์ฌ์ค์น. |
pnpm release:canary |
Canary ๋ฆด๋ฆฌ์ค ๋น๋ ๋ฐ ๋ฐฐํฌ (Git ํ๊ทธ ์์). |
pnpm release |
์์ ๋ฆด๋ฆฌ์ค ๋น๋ ๋ฐ ๋ฐฐํฌ. |
ESLint์ Prettier๊ฐ ๋ฆฐํธ์ ์ฝ๋ ํฌ๋งทํ ์ ์ํด ์ค์ ๋์ด ์์ต๋๋ค. ์ปค์คํ ์ค์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
- ESLint Config:
@naverpay/eslint-config - Prettier Config:
@naverpay/prettier-config
Git ์ปค๋ฐ ์ lint-staged๋ฅผ ํตํด ์๋์ผ๋ก ๋ฆฐํธ ๋ฐ ํฌ๋งทํ
์ด ์ ์ฉ๋ฉ๋๋ค.
Markdown ํ์ผ์ ์ผ๊ด์ฑ์ ์ ์งํ๊ธฐ ์ํด @naverpay/markdown-lint๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์๋ ์คํ:
pnpm markdownlint
pnpm markdownlint:fix๋ฒ์ ๊ด๋ฆฌ ๋ฐ ๋ฐฐํฌ๋ Changesets๋ฅผ ์ฌ์ฉํฉ๋๋ค.
- ๋ ํฌ์งํ ๋ฆฌ๋ฅผ ํฌํฌํ๊ณ ์ ๋ธ๋์น๋ฅผ ์์ฑํฉ๋๋ค.
- ๋ชจ๋ ๋ฆฐํธ ๋ฐ ํ ์คํธ๋ฅผ ํต๊ณผํ๋๋ก ์ฝ๋๋ฅผ ์์ ํฉ๋๋ค.
- ํ ๋ฆฌํ์คํธ๋ฅผ ์ ์ถํฉ๋๋ค.
๊ฐ์ ์ ์ด๋ ๋ฌธ์ ์ ์ด ์๋ค๋ฉด ๋ ํฌ์งํ ๋ฆฌ์ Issue๋ฅผ ์ด์ด์ฃผ์ธ์.
์ด ํ ํ๋ฆฟ์ ๋ค์ด๋ฒ ํ์ด๋ธ์ ์ ์ ํ๋ซํผ ์ฐํ ๊ณตํต๊ฐ๋ฐTF (@NaverPayDev/frontend)์ ์ํด ๊ด๋ฆฌ๋๋ฉฐ, ํด๋น ๋ผ์ด์ ์ค ์ ์ฑ ์ ๋ฐ๋ฆ ๋๋ค.