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:

    typescript
    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())
    })
    Dica
    O endpoint /metrics deve ser protegido em produção — exponha apenas para o Prometheus internamente (sem acesso externo) ou adicione autenticação básica. Métricas podem revelar padrões de uso da aplicação.

    Métricas de requisições HTTP com middleware

    Rastreie latência e volume de requisições por endpoint:

    typescript
    // 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:

    typescript
    // 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 query

    Métricas de fila e background jobs

    Monitore o estado de filas e workers para detectar backlog:

    typescript
    // 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"} > 100

    Queries PromQL para aplicação Node.js

    Queries para dashboards e alertas da aplicação:

    promql
    # 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.

    Perguntas frequentes