Monitoramento vs. observabilidade
Monitorar é vigiar sinais que você já sabe que importam (o servidor está vivo? quanta CPU ele usa?). Observabilidade é poder responder perguntas que não tinha antecipado a partir do que o sistema emite. A diferença prática: quando algo falha às 3 da madrugada, você tem dados suficientes para entender por quê, sem fazer deploy de código novo?
Esses dados se apoiam em três pilares: logs, métricas e traces. São complementares, não intercambiáveis.
1. Logs estruturados
Um log é um registro de um evento pontual. O erro clássico é escrever texto
livre (console.log("usuário " + id + " fez login")): legível para uma
pessoa, inservível para uma máquina. Um log estruturado é um objeto (que se
serializa em JSON) com campos consistentes:
{ "nivel": "info", "mensagem": "login", "usuarioId": 42, "ts": "2026-06-22T10:00:00Z", "requestId": "abc-123" }
Assim você pode filtrar e agregar: "me dê todos os error do usuarioId
42 na última hora". Cada log carrega um nível que indica sua gravidade e
permite silenciar o ruído em produção:
debug: detalhe interno, só em desenvolvimento.info: eventos normais esperados (uma requisição, um login).warn: algo estranho mas recuperável (uma nova tentativa, um cache frio).error: uma operação falhou e alguém deveria olhar.
2. Métricas
Uma métrica é um número agregado no tempo, barato de armazenar (você não guarda cada evento, apenas sua contagem ou distribuição). Tipos comuns:
- Contador (counter): só sobe. "Número de requisições", "erros totais". Você deriva a taxa (requisições por segundo) a partir de sua inclinação.
- Medidor (gauge): sobe e desce. "Conexões abertas", "memória usada".
- Histograma: agrupa muitas medições em buckets para ver sua distribuição. É o que você usa para a latência.
Sobre a latência, nunca olhe só a média: uma média de 100 ms pode esconder que 1 a cada 20 usuários espera 3 segundos. Por isso se usam percentis. O p95 é o valor abaixo do qual cai 95 % das requisições: "95 % responde em menos de 200 ms". O p99 captura a cauda, a pior experiência. Melhorar o p95/p99 costuma importar mais do que melhorar a média.
3. Traces (distributed tracing)
Num sistema com vários serviços, uma única requisição do usuário cruza muitos saltos: gateway → serviço de pedidos → banco de dados → serviço de pagamentos. Um trace segue essa requisição de ponta a ponta. Cada salto é um span com sua duração, e todos compartilham um mesmo request id (ou trace id) que se propaga nos cabeçalhos. Assim você vê onde o tempo se vai: se a requisição leva 800 ms, o trace te diz que 700 foram numa consulta lenta ao BD.
Esse mesmo requestId deve ir também nos logs: é o fio que costura os três
pilares. Com ele você salta de "esta requisição foi lenta" (trace) para "e além
disso registrou este erro" (log).
O que você constrói por cima
- Dashboards: gráficos das métricas-chave (taxa de erros, p95, tráfego).
- Alertas: regras que avisam quando uma métrica cruza um limite ("p95 > 1 s durante 5 min"). Um bom alerta é acionável: se ninguém vai fazer nada ao recebê-lo, é ruído.
- Health checks: um endpoint (
/health) que responde se o serviço está saudável. O balanceador o consulta para parar de enviar tráfego a instâncias caídas.
Regra prática: instrumente primeiro os golden signals — latência, tráfego, erros e saturação. Cobrem a maioria dos incidentes.
Exemplos
Um log estruturado em JSON, pronto para indexar
function log(nivel, mensagem, contexto = {}) {
return JSON.stringify({
nivel,
mensagem,
ts: new Date().toISOString(),
...contexto,
});
}
console.log(log("error", "pagamento recusado", { usuarioId: 42, requestId: "abc-123" }));
p95: o percentil 95 de uma lista de latências (ms)
function percentil(valores, p) {
const ordem = [...valores].sort((a, b) => a - b);
const i = Math.ceil((p / 100) * ordem.length) - 1;
return ordem[Math.max(0, i)];
}
const latencias = [80, 90, 95, 100, 110, 120, 130, 140, 150, 900];
console.log("p95:", percentil(latencias, 95), "ms"); // a cauda aparece