
Monitoramento de APIs em produção: métricas e alertas
Existem duas formas de descobrir que sua API está com problemas em produção: seus alertas te avisam, ou seus clientes te avisam. A primeira é apenas um incidente. A segunda é um incidente e uma crise de confiança.
Monitoramento de API em produção não é opcional — é a infraestrutura de qualidade que diferencia um serviço profissional de um protótipo em produção. E com as ferramentas certas, configurar observabilidade básica leva menos de um dia de trabalho.
Métricas Essenciais: Latência, Error Rate e Throughput
As três métricas fundamentais de qualquer API são conhecidas como os "Golden Signals" do SRE (Site Reliability Engineering):
Latência — quanto tempo sua API demora para responder. O erro clássico é monitorar apenas a média. A média esconde outliers: se 95% das requisições demoram 50ms e 5% demoram 10 segundos, a média pode ser 550ms — que parece razoável mas representa uma péssima experiência para 1 em cada 20 usuários.
Os percentis corretos para monitorar:
- p50 (mediana): O usuário "mediano". Boa baseline de performance.
- p95: 95% das requisições estão abaixo desse valor. O que a maioria dos usuários experimenta.
- p99: O "cauda longa". Onde moram os problemas de performance reais.
- p99.9: Para SLAs críticos. Uma API com p99.9 de 2 segundos tem 0.1% das requisições mais lentas que isso — ainda são centenas de requisições em alto volume.
Error Rate — percentual de requisições que retornam 5xx. Um spike súbito de 0% para 5% de error rate é mais significativo do que uma error rate constante de 2%. Alerte em variações relativas, não apenas em limites absolutos.
Throughput — quantas requisições por segundo. Útil para detectar tanto quedas de tráfego anormais (algo quebrou upstream) quanto picos que podem indicar abuso ou tráfego incomum.
// Instrumentação manual com métricas customizadas no Next.js
import { metrics } from "@opentelemetry/api";
const meter = metrics.getMeter("api-metrics");
const httpRequestDuration = meter.createHistogram("http_request_duration_ms", {
description: "Duração de requisições HTTP em milliseconds",
unit: "ms",
});
const httpRequestsTotal = meter.createCounter("http_requests_total", {
description: "Total de requisições HTTP",
});
// Middleware de instrumentação
export function instrumentRequest(handler: NextApiHandler): NextApiHandler {
return async (req, res) => {
const startTime = Date.now();
const labels = {
method: req.method ?? "unknown",
route: req.url?.split("?")[0] ?? "unknown",
};
try {
await handler(req, res);
const duration = Date.now() - startTime;
httpRequestDuration.record(duration, { ...labels, status: String(res.statusCode) });
httpRequestsTotal.add(1, { ...labels, status: String(res.statusCode) });
} catch (error) {
httpRequestDuration.record(Date.now() - startTime, { ...labels, status: "500" });
httpRequestsTotal.add(1, { ...labels, status: "500" });
throw error;
}
};
}
OpenTelemetry: Distributed Tracing na Prática
Métricas dizem "algo está errado". Traces dizem "exatamente onde está errado e por quê". OpenTelemetry (OTel) é o padrão aberto para instrumentação de observabilidade — funciona com qualquer backend (Jaeger, Tempo, Datadog, New Relic, Honeycomb).
Um trace é composto por spans: unidades de trabalho com timestamp de início, duração e atributos. Uma requisição HTTP cria um span raiz; chamadas ao banco de dados, serviços externos e filas criam spans filhos. O resultado é um gráfico de cascata que mostra exatamente onde o tempo foi gasto.
// Configuração do OpenTelemetry no Next.js (instrumentation.ts)
import { NodeSDK } from "@opentelemetry/sdk-node";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
export function register() {
const sdk = new NodeSDK({
traceExporter: new OTLPTraceExporter({
url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT ?? "http://localhost:4318/v1/traces",
}),
metricReader: new PeriodicExportingMetricReader({
exporter: new OTLPMetricExporter({
url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT ?? "http://localhost:4318/v1/metrics",
}),
}),
instrumentations: [
getNodeAutoInstrumentations({
"@opentelemetry/instrumentation-fs": { enabled: false }, // muito verboso
}),
],
serviceName: "api-pedidos",
});
sdk.start();
}
// Criando spans customizados para operações críticas
import { trace } from "@opentelemetry/api";
const tracer = trace.getTracer("order-service");
async function processPayment(orderId: string, amount: number) {
const span = tracer.startSpan("process_payment", {
attributes: {
"order.id": orderId,
"payment.amount": amount,
},
});
try {
const result = await paymentGateway.charge({ orderId, amount });
span.setAttribute("payment.transaction_id", result.transactionId);
span.setStatus({ code: SpanStatusCode.OK });
return result;
} catch (error) {
span.recordException(error as Error);
span.setStatus({ code: SpanStatusCode.ERROR, message: String(error) });
throw error;
} finally {
span.end();
}
}
Com auto-instrumentações, você ganha gratuitamente traces de: HTTP requests, Prisma/TypeORM queries, Redis commands, chamadas fetch/axios e mensagens de fila. O span tree revela imediatamente se a lentidão está no banco, em um serviço externo ou no código da aplicação.
Grafana + Prometheus: Dashboard de API em 30 Minutos
Prometheus scrape métricas expondo um endpoint HTTP em formato de texto. Grafana visualiza essas métricas em dashboards. A combinação é o padrão de observabilidade mais comum em sistemas self-hosted.
# docker-compose.yml — stack de observabilidade local
version: "3.8"
services:
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
grafana:
image: grafana/grafana:latest
ports:
- "3001:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana-data:/var/lib/grafana
tempo:
image: grafana/tempo:latest
ports:
- "4317:4317" # OTLP gRPC
- "4318:4318" # OTLP HTTP
- "3200:3200" # Tempo API
volumes:
grafana-data:
Queries Prometheus essenciais para dashboards de API:
# Latência p99 por rota (últimos 5 minutos)
histogram_quantile(0.99,
rate(http_request_duration_ms_bucket[5m])
) by (route)
# Error rate por rota
sum(rate(http_requests_total{status=~"5.."}[5m])) by (route)
/
sum(rate(http_requests_total[5m])) by (route)
# Throughput (req/s)
sum(rate(http_requests_total[1m])) by (route)
# Apdex score: % de requisições dentro do SLA (ex.: 500ms)
(
sum(rate(http_request_duration_ms_bucket{le="500"}[5m]))
+
sum(rate(http_request_duration_ms_bucket{le="2000"}[5m]))
) / 2
/
sum(rate(http_request_duration_ms_count[5m]))
Grafana tem dashboards prontos no grafana.com/grafana/dashboards para Node.js, Next.js e APIs genéricas. Importe, ajuste as queries para seus label names e você tem observabilidade profissional em minutos.
Alertas Inteligentes: Evitando Alert Fatigue
Alert fatigue é o fenômeno onde um time para de responder a alertas porque recebe tantos alertas sem urgência real que os relevantes se perdem no ruído. É um dos problemas mais sérios em operações de software.
Os princípios de alertas inteligentes:
Alerte em sintomas, não em causas. "Error rate > 5%" é um sintoma: algo está errado para os usuários. "CPU > 80%" é uma causa: pode ou não estar afetando usuários. Prefira alertas de sintoma, use causa como contexto no runbook.
Burn rate, não limites absolutos. Em vez de alertar quando error rate > 1%, alerte quando você está "queimando" seu SLO mais rápido que o sustentável. Se seu SLO é 99.9% de disponibilidade/mês e você está com 10% de error rate, você vai esgotar o budget de erros do mês inteiro em 4 horas.
# Alertas no Prometheus (alertmanager)
groups:
- name: api-alerts
rules:
# Alta urgência: queimando SLO rapidamente
- alert: HighErrorBurnRate
expr: |
(
sum(rate(http_requests_total{status=~"5.."}[1h]))
/ sum(rate(http_requests_total[1h]))
) > 0.05
for: 5m
labels:
severity: critical
team: backend
annotations:
summary: "Error rate acima de 5% por 5 minutos"
runbook: "https://wiki.empresa.com/runbooks/high-error-rate"
# Latência degradando
- alert: HighP99Latency
expr: |
histogram_quantile(0.99,
rate(http_request_duration_ms_bucket[5m])
) > 2000
for: 3m
labels:
severity: warning
annotations:
summary: "P99 de latência acima de 2 segundos"
# Ausência de tráfego (possível falha upstream)
- alert: NoTraffic
expr: sum(rate(http_requests_total[5m])) < 0.1
for: 10m
labels:
severity: warning
annotations:
summary: "API sem tráfego por 10 minutos — verificar se está acessível"
Três níveis de severidade:
- Critical: acorde alguém agora. SLO em risco imediato, usuários impactados.
- Warning: investigue durante o horário de trabalho. Tendência preocupante.
- Info: log para auditoria. Não interrompe ninguém.
Conclusão
Observabilidade de API não é um projeto futuro — é um requisito de produção. A boa notícia é que o custo de entrada caiu drasticamente: OpenTelemetry é gratuito e open source, Grafana + Prometheus pode ser self-hosted com custo zero, e a configuração básica leva menos de um dia de trabalho.
O retorno é imediato: próxima vez que um cliente reclamar de lentidão, você terá dados precisos de qual endpoint, em qual percentil de latência, a partir de qual momento — não achismo. Próxima vez que um incidente acontecer, você saberá antes do cliente.
No SystemForge, monitoramento e SLOs fazem parte da fase de deploy — não são adicionados depois como pensamento tardio. Isso significa que cada sistema entregado vem com dashboards funcionais, alertas configurados e runbooks básicos. Se você está construindo uma API que vai para produção e precisa de observabilidade desde o início, podemos ajudar a estruturar isso como parte do projeto.
Precisa de API e Integrações?
Desenvolvemos APIs robustas e integramos com qualquer sistema.
Saiba mais →Precisa de ajuda?

