Métricas de Node.js com Prometheus
Node Exporter monitora o sistema operacional, mas não sua aplicação. prom-client é a biblioteca oficial do Prometheus para Node.js — com ela você expõe métricas de negócio: latência por endpoint, número de usuários ativos, erros de banco por tipo, filas pendentes. Esses dados são o que realmente importa para SLOs e debugging.
Instalar prom-client e expor /metrics
prom-client é a biblioteca oficial — expõe métricas de runtime do Node.js automaticamente e permite métricas customizadas:
npm install prom-client
// src/metrics.ts
import { Registry, collectDefaultMetrics } from 'prom-client'
export const registry = new Registry()
// Coletar métricas padrão do Node.js automaticamente:
// process_cpu_seconds_total, process_memory_bytes,
// nodejs_heap_size_bytes, nodejs_eventloop_lag_seconds, etc.
collectDefaultMetrics({
register: registry,
prefix: 'minha_api_', // prefixo para identificar a aplicação
gcDurationBuckets: [0.001, 0.01, 0.1, 1, 2, 5],
})
// src/index.ts
import express from 'express'
import { registry } from './metrics'
const app = express()
// Endpoint que o Prometheus irá coletar
app.get('/metrics', async (req, res) => {
res.set('Content-Type', registry.contentType)
res.send(await registry.metrics())
})Métricas de requisições HTTP com middleware
Rastreie latência e volume de requisições por endpoint:
// src/middleware/metrics.ts
import { Histogram, Counter, Gauge, Registry } from 'prom-client'
import { Request, Response, NextFunction } from 'express'
export function createHttpMetrics(registry: Registry) {
const httpDuration = new Histogram({
name: 'http_request_duration_seconds',
help: 'Duração das requisições HTTP em segundos',
labelNames: ['method', 'route', 'status_code'],
buckets: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5],
registers: [registry],
})
const httpRequestsTotal = new Counter({
name: 'http_requests_total',
help: 'Total de requisições HTTP',
labelNames: ['method', 'route', 'status_code'],
registers: [registry],
})
const httpActiveRequests = new Gauge({
name: 'http_active_requests',
help: 'Número de requisições ativas',
registers: [registry],
})
return (req: Request, res: Response, next: NextFunction) => {
const start = Date.now()
httpActiveRequests.inc()
res.on('finish', () => {
const duration = (Date.now() - start) / 1000
const route = req.route?.path || 'unknown'
const labels = { method: req.method, route, status_code: res.statusCode }
httpDuration.observe(labels, duration)
httpRequestsTotal.inc(labels)
httpActiveRequests.dec()
})
next()
}
}Métricas de negócio customizadas
Meça o que importa para o seu negócio — não só infraestrutura:
// src/metrics/business.ts
import { Counter, Gauge, Histogram } from 'prom-client'
import { registry } from '../metrics'
// Contagem de usuários registrados
export const usersRegistered = new Counter({
name: 'users_registered_total',
help: 'Total de usuários registrados',
registers: [registry],
})
// Usuários online agora
export const activeUsers = new Gauge({
name: 'active_users',
help: 'Usuários ativos no momento',
registers: [registry],
})
// Latência de operações de banco
export const dbQueryDuration = new Histogram({
name: 'db_query_duration_seconds',
help: 'Duração de queries no banco de dados',
labelNames: ['operation', 'table'],
buckets: [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1],
registers: [registry],
})
// Uso nas rotas:
// usersRegistered.inc() — ao registrar usuário
// activeUsers.set(await countOnlineUsers()) — periodicamente
// const end = dbQueryDuration.startTimer() — antes da query
// end({ operation: 'select', table: 'users' }) — após a queryMétricas de fila e background jobs
Monitore o estado de filas e workers para detectar backlog:
// src/metrics/queue.ts
import { Gauge, Counter } from 'prom-client'
import { registry } from '../metrics'
export const queueSize = new Gauge({
name: 'queue_pending_jobs',
help: 'Jobs pendentes na fila',
labelNames: ['queue_name'],
registers: [registry],
})
export const jobsProcessed = new Counter({
name: 'jobs_processed_total',
help: 'Jobs processados',
labelNames: ['queue_name', 'status'], // status: success | failed
registers: [registry],
})
// Atualizar tamanho da fila periodicamente
setInterval(async () => {
const pendingJobs = await getQueueSize('emails')
queueSize.set({ queue_name: 'emails' }, pendingJobs)
}, 15000)
// PromQL para alertar quando fila cresce:
// queue_pending_jobs{queue_name="emails"} > 100Queries PromQL para aplicação Node.js
Queries para dashboards e alertas da aplicação:
# Taxa de requisições por segundo (últimos 5 min)
rate(http_requests_total[5m])
# Percentil 99 de latência por rota
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))
# Taxa de erros (%)
rate(http_requests_total{status_code=~"5.."}[5m]) /
rate(http_requests_total[5m]) * 100
# Heap do Node.js usado (%)
nodejs_heap_size_used_bytes / nodejs_heap_size_total_bytes * 100
# Event loop lag (ms)
nodejs_eventloop_lag_seconds * 1000
# Requests ativas agora
http_active_requests
# SLO: % de requests respondidas em < 500ms
rate(http_request_duration_seconds_bucket{le="0.5"}[5m]) /
rate(http_request_duration_seconds_count[5m]) * 100$ runstack deploy --plan starter
Não quer configurar manualmente?
Não quer configurar manualmente? Implante o VPS em menos de 3 minutos com a Runstack. Infraestrutura da OPEN DATACENTER, com servidores no Brasil.