Todo sistema em produção tem um dia ruim. A diferença está em quem descobre primeiro: você ou quem usa. Num SaaS, o cliente abre um chamado. Num ERP, a nota fiscal não sai e o fechamento do mês trava. Num sistema interno, ninguém reclama: as pessoas só voltam para a planilha.
Observabilidade é a capacidade de responder "o que está acontecendo e por quê?" olhando para os dados que o sistema já emite, sem precisar subir um deploy novo cheio de console.log.
Este post junta os conceitos, o que medir primeiro, as ferramentas (gratuitas, pagas e self-hosted), quanto custam e como a arquitetura muda quando o sistema cresce. No fim tem um checklist para aplicar em qualquer projeto.
Monitoramento ou observabilidade?
Monitoramento responde perguntas que você já conhecia: "a CPU passou de 90%?", "o site está no ar?".
Observabilidade responde perguntas que você não previu: "por que só os clientes do plano Enterprise estão com o relatório lento desde terça?".
Os dois se completam. O monitoramento avisa que algo quebrou; a observabilidade ajuda a descobrir o quê.
Os sinais
| Sinal | O que é | Responde | Exemplo |
|---|---|---|---|
| Logs | Registros de eventos, com contexto | O que aconteceu, em detalhe? | pedido 4821 falhou: timeout no gateway |
| Métricas | Números agregados ao longo do tempo | Quanto? Está piorando? | Requisições por segundo, latência p95, tamanho da fila |
| Traces | O caminho de uma requisição por todos os serviços | Onde o tempo foi gasto? | API → banco (40 ms) → serviço fiscal (2,1 s) |
| Profiles | Onde o código gasta CPU e memória | Qual função pesa? | 60% da CPU no parser de XML |
| RUM | Dados do navegador de quem usa | Como está para o usuário real? | LCP, erros de JavaScript, cliques sem resposta |
Regra prática: métricas avisam, traces localizam, logs explicam.
O que medir primeiro
Não comece instrumentando tudo. Comece pelo que diz se o usuário está sendo atendido.
RED, para tudo que recebe requisição
- Rate: requisições por segundo.
- Errors: porcentagem que falha.
- Duration: latência em percentis (p50, p95, p99). Média esconde o problema: se 5% das requisições levam 8 segundos, a média ainda parece ótima.
USE, para recursos
Utilization, Saturation e Errors de CPU, memória, disco, conexões do banco e filas. Saturação costuma ser o mais revelador: uma fila que só cresce ou um pool de conexões sempre cheio avisam antes da CPU.
Métricas de negócio
Muitas vezes são as mais úteis: notas emitidas por hora, pedidos finalizados, boletos gerados, logins. Se a emissão de notas cai a zero numa terça às 10h, algo quebrou, mesmo com a CPU tranquila e nenhum erro registrado.
SLOs: quanto erro é aceitável
Um SLI é o que você mede (por exemplo, % de requisições com sucesso em menos de 500 ms). Um SLO é a meta (99,5% em 30 dias). A diferença, 0,5%, é o error budget: quanto de falha dá para gastar antes de pausar features e cuidar da estabilidade.
| SLO | Indisponibilidade permitida por mês |
|---|---|
| 99% | ~7 h 18 min |
| 99,5% | ~3 h 39 min |
| 99,9% | ~44 min |
| 99,99% | ~4 min |
Cada 9 a mais custa bem mais caro. Um sistema interno usado em horário comercial raramente precisa de 99,9%.
OpenTelemetry: instrumente uma vez
OpenTelemetry (OTel) é o padrão aberto da CNCF para gerar e enviar logs, métricas e traces. Quase todas as ferramentas deste post aceitam OTel: você instrumenta o código uma vez e troca de fornecedor mudando uma configuração, não o código.
Este é o conselho mais importante do post: não amarre o código ao SDK proprietário de um fornecedor. Preço muda, a empresa cresce, e trocar de ferramenta não deveria exigir reescrever a instrumentação.
No Next.js, o framework já vem instrumentado. Basta um instrumentation.ts na raiz do projeto (ou dentro de src):
import { registerOTel } from "@vercel/otel";
export function register() {
registerOTel({ serviceName: "erp-api" });
}Para medir uma operação específica, crie um span:
import { SpanStatusCode, trace } from "@opentelemetry/api";
const tracer = trace.getTracer("faturamento");
export async function emitirNota(pedidoId: string) {
return tracer.startActiveSpan("emitir-nota", async (span) => {
span.setAttribute("pedido.id", pedidoId);
try {
return await enviarParaSefaz(pedidoId);
} catch (err) {
span.recordException(err as Error);
span.setStatus({ code: SpanStatusCode.ERROR });
throw err;
} finally {
span.end();
}
});
}O destino dos dados vem de variáveis de ambiente padrão, como OTEL_EXPORTER_OTLP_ENDPOINT, e não do código. Java, .NET, Python, Go e PHP têm SDKs equivalentes, e vários oferecem instrumentação automática, sem mexer no código.
Logs que ajudam de verdade
Estruturados (JSON), não texto solto. Assim dá para filtrar por campo:
Texto tenant_id = 42 AND level = errorCom
trace_id. É o que liga o log ao trace: do erro você chega à requisição inteira, e vice-versa.Níveis com critério:
erroré algo que alguém precisa olhar;warné algo estranho que se resolveu sozinho;infosão eventos de negócio;debugfica desligado em produção.Sem dados pessoais. CPF, e-mail, token, senha e dados de cartão não vão para o log. Pela LGPD, log também é tratamento de dado pessoal, e ele costuma parar em lugares com menos controle de acesso que o banco.
{
"time": "2026-10-16T13:04:22.118Z",
"level": "error",
"service": "erp-api",
"tenant_id": "42",
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"msg": "falha ao emitir nota",
"pedido_id": "4821",
"erro": "timeout após 30s",
"tentativa": 3
}As ferramentas
Open source e self-hosted
Grátis na licença, não na operação: você paga em servidor, disco e horas de alguém cuidando.
| Ferramenta | Para quê | Observação |
|---|---|---|
| Prometheus | Métricas | O padrão de fato. Coleta por pull, consultas em PromQL, alertas com Alertmanager |
| Grafana | Dashboards e alertas | Lê de quase tudo: Prometheus, Loki, Postgres, Elasticsearch, CloudWatch |
| Loki | Logs | Indexa só os labels, não o texto. Barato de manter, guarda em object storage (S3) |
| Tempo | Traces | Também em object storage; no Grafana, liga trace, log e métrica |
| Mimir / VictoriaMetrics | Métricas em escala | Quando um Prometheus sozinho não aguenta: retenção longa, alta disponibilidade, multi-tenant |
| Jaeger | Traces | Projeto da CNCF, simples para começar |
| SigNoz | Tudo em um | Logs, métricas e traces sobre ClickHouse, nativo de OTel |
| Elastic / OpenSearch | Logs e busca | Excelente para busca em texto; pesado em memória e disco |
| Sentry / GlitchTip | Erros | Stack trace, usuário afetado e release. O Sentry self-hosted é pesado; o GlitchTip é leve e aceita o SDK do Sentry |
| Uptime Kuma | Uptime | Checa HTTP, TCP e DNS e alerta no Telegram, Slack ou e-mail. Sobe num container |
| Netdata | Servidores | Métricas de máquina em tempo real, quase sem configuração |
| OTel Collector | Pipeline | Recebe, filtra, amostra e encaminha a telemetria para um ou mais destinos |
A combinação mais comum, e que cobre bem a maioria dos casos, é OTel Collector + Prometheus + Loki + Tempo + Grafana. Dá para começar num único servidor com Docker Compose, e para testar localmente existe a imagem grafana/otel-lgtm, com tudo junto num container só.
Planos gratuitos de SaaS
Para começar sem servidor nenhum. Valores de outubro de 2026; confira a página oficial, porque mudam com frequência.
| Serviço | O que o plano grátis inclui |
|---|---|
| Grafana Cloud | 10 mil séries de métricas ativas, 50 GB de logs, 50 GB de traces, 14 dias de retenção |
| New Relic | 100 GB de dados por mês e 1 usuário com acesso completo |
| Sentry | 5 mil erros por mês, 1 usuário |
| Honeycomb | 20 milhões de eventos por mês (cada span conta como um evento) |
| Better Stack | Monitores de uptime, status page e um volume pequeno de logs |
Para um sistema interno ou um SaaS no começo, Sentry (erros) + Grafana Cloud (métricas, logs e traces) + um monitor de uptime costuma caber no plano grátis por um bom tempo.
Plataformas pagas
| Plataforma | Como cobra | Ponto forte |
|---|---|---|
| Datadog | Por host, por GB e por métrica customizada | Tudo integrado, centenas de integrações prontas |
| New Relic | Por GB ingerido e por usuário | Previsível para times pequenos com muito dado |
| Dynatrace | Por host/memória e por consumo | Descoberta automática e análise de causa raiz; forte em grandes empresas |
| Honeycomb | Por evento | Investigar com alta cardinalidade: filtrar por qualquer campo, até id de cliente |
| Grafana Cloud | Por série, por GB e por usuário | O stack open source gerenciado, sem lock-in |
| Elastic Cloud | Por recursos (memória e armazenamento) | Busca em logs |
| Amazon CloudWatch, Azure Monitor, Google Cloud Observability | Por GB, por métrica e por consulta | Já vem integrado quando toda a infraestrutura está naquela nuvem |
Para ter uma ordem de grandeza, o Datadog em preço de lista anual: cerca de US$ 15 por host/mês para infraestrutura e US$ 31 por host/mês para APM. Logs são cobrados duas vezes: US$ 0,10 por GB ingerido e mais um valor por milhão de eventos indexados. Dez servidores com APM já passam de US$ 450 por mês antes de qualquer log.
As armadilhas de custo
A conta de observabilidade quase nunca explode pelo plano. Explode pelo volume.
- Cardinalidade. Cada combinação única de labels vira uma série. Uma métrica
http_requestscomrota(50) ×status(5) ×metodo(4) são 1.000 séries. Acrescenteuser_idcom 20 mil usuários e são 20 milhões. Nunca use id de usuário, pedido ou requisição como label de métrica; isso vai em traces e logs. - Debug em produção. Um
log.debugdentro de um loop pode gerar mais GB que o resto do sistema inteiro. - Retenção. Guardar tudo por um ano raramente faz sentido. Erros e traces: 15 a 30 dias. Métricas agregadas: meses. Logs de auditoria: o que a lei ou o contrato exigir, em armazenamento barato.
- Health checks. O load balancer bate no
/healtha cada poucos segundos, e cada batida vira log e trace. Filtre antes de pagar por eles. - Cobrança por host com autoscaling. Com Kubernetes ou autoscaling, o número de hosts varia, e alguns fornecedores cobram pelo pico do mês.
Self-hosted ou SaaS?
| Critério | Self-hosted | SaaS |
|---|---|---|
| Custo para começar | Baixo (um servidor) | Zero no plano grátis |
| Custo em escala | Menor por GB, mas inclui gente | Cresce com o volume, às vezes rápido |
| Operação | Upgrade, disco, backup e alta disponibilidade são seus | Problema do fornecedor |
| Dados sensíveis e LGPD | Ficam na sua infraestrutura | Avaliar contrato, região e o que é enviado |
| Tempo até o primeiro dashboard | Horas a dias | Minutos |
| Quem monitora o monitoramento? | Você | O fornecedor |
A regra que eu sigo: comece em SaaS, com OpenTelemetry no código. Considere self-hosted quando a conta passar do custo de um servidor mais algumas horas de manutenção por mês, ou quando houver exigência de que os dados não saiam da sua infraestrutura. Como o código fala OTel, migrar é trocar o destino no Collector.
Uma pegadinha do self-hosted: se o servidor de monitoramento cai junto com o sistema, você fica cego justo quando mais precisa. Mantenha pelo menos um monitor de uptime fora da sua infraestrutura.
Como escalar
A observabilidade cresce em fases, junto com o sistema.
Fase 1: um app, um banco
- Erros com stack trace (Sentry ou GlitchTip).
- Monitor de uptime externo nos endpoints principais.
- Logs estruturados, centralizados num lugar só.
- Um painel com RED da API e as principais métricas de negócio.
- Alertas para: sistema fora do ar, taxa de erro alta, fila parada.
Isso já resolve a maior parte dos incidentes de um sistema interno ou de um SaaS pequeno.
Fase 2: alguns serviços, filas e integrações
- Traces distribuídos com OTel, para seguir uma requisição da API até o worker e a integração externa.
trace_idem todos os logs.- SLOs para os fluxos críticos: login, checkout, emissão de nota.
- Um OTel Collector entre os apps e o destino, para filtrar e rotear sem mexer nos apps.
Fase 3: muitos serviços, muitos times, muito volume
- Collector em duas camadas: um agente em cada máquina ou nó (coleta local, pouco processamento) e um gateway central (amostragem, filtros, roteamento).
- Amostragem de traces. Guardar 100% dos traces de um sistema com milhões de requisições é caro e quase inútil. Há dois jeitos:
- Head sampling: decide no início da requisição (guarda 10%, por exemplo). Simples e barato, mas pode descartar justo o trace do erro.
- Tail sampling: decide no fim, depois de ver o trace inteiro. Guarda todos os erros e requisições lentas e só uma amostra do resto. Exige um gateway que segure os spans na memória por alguns segundos.
- Métricas derivadas de traces: o Collector calcula RED a partir dos spans antes de amostrar, então as métricas continuam exatas mesmo guardando 5% dos traces.
- Armazenamento em camadas: dados recentes em disco rápido, antigos em object storage (S3, R2, GCS). Loki, Tempo e Mimir já funcionam assim.
- Métricas em escala: Prometheus sozinho vai até certo ponto; depois entram Mimir, VictoriaMetrics ou Thanos, para alta disponibilidade e retenção longa.
- Governança: nomes padronizados (as semantic conventions do OTel), limite de cardinalidade por time e um dono para cada dashboard e alerta.
Um gateway com filtro de health check e tail sampling fica assim (processadores da distribuição contrib do Collector):
receivers:
otlp:
protocols:
grpc:
http:
processors:
# Descarta health checks antes de pagar por eles
filter/health:
error_mode: ignore
traces:
span:
- 'attributes["url.path"] == "/health"'
# Guarda todos os erros, tudo acima de 1 s e 10% do resto
tail_sampling:
decision_wait: 10s
policies:
- name: erros
type: status_code
status_code: { status_codes: [ERROR] }
- name: lentos
type: latency
latency: { threshold_ms: 1000 }
- name: amostra
type: probabilistic
probabilistic: { sampling_percentage: 10 }
batch:
exporters:
otlphttp:
endpoint: https://otlp.exemplo.com.br
service:
pipelines:
traces:
receivers: [otlp]
processors: [filter/health, tail_sampling, batch]
exporters: [otlphttp]Com mais de uma instância do gateway, todos os spans de um mesmo trace precisam cair na mesma instância. Para isso, a camada de agentes usa o exporter loadbalancing, que distribui por trace_id.
Alertas que não viram ruído
- Alerte no sintoma, não na causa. "Taxa de erro do checkout acima de 2% por 5 minutos" é acionável. "CPU em 85%" muitas vezes não é: se o usuário está bem, ninguém precisa acordar.
- Alerte pelo consumo do error budget (burn rate): avisa quando, no ritmo atual, o SLO do mês vai estourar. Pega tanto quedas bruscas quanto degradação lenta.
- Todo alerta tem dono e runbook: o que olhar primeiro, como mitigar, quem chamar.
- Dois níveis: o que acorda alguém (sistema fora, dinheiro parado) e o que vira tarefa para o dia seguinte.
- Revise todo mês. Alerta que dispara e ninguém age deve ser ajustado ou apagado.
Ferramentas de plantão como o PagerDuty, ou a gestão de incidentes do Grafana e do Better Stack, organizam escala e escalonamento. Para times pequenos, um canal no Slack ou no Telegram bem filtrado resolve.
Por tipo de sistema
SaaS
tenant_idem todo log e trace. A pergunta mais comum do suporte é "o que aconteceu com o cliente X?".- SLO por plano ou por cliente grande. A média do sistema pode estar ótima enquanto um cliente está péssimo.
- Vizinho barulhento: um tenant que importa 1 milhão de linhas pode degradar todo mundo. Métricas de uso por tenant mostram isso (com cuidado de cardinalidade se forem milhares de tenants).
- Erros de front-end e RUM: boa parte do que o cliente sente acontece no navegador, não na API.
- Status page pública: reduz chamados durante um incidente.
ERP
- Jobs agendados são o coração: fechamento, conciliação, folha, importação de extrato. O erro mais perigoso é o job que não roda: não gera erro nem log. Use um heartbeat (dead man's switch): o job avisa quando termina, e o alerta dispara se o aviso não chegar. O Healthchecks.io e o Uptime Kuma (monitor do tipo push) fazem isso.
- Integrações externas: SEFAZ, bancos, gateways de pagamento e transportadoras caem e ficam lentos. Meça latência e erro por integração, com timeouts e retries visíveis.
- Filas: tamanho da fila, idade da mensagem mais antiga e o que caiu na dead letter queue.
- Picos previsíveis: fim de mês, fechamento fiscal, folha. Compare com o mesmo período do mês anterior, não com a semana passada.
- Banco de dados: consultas lentas (
pg_stat_statementsno Postgres, Query Store no SQL Server), locks e conexões. Em ERP, o gargalo quase sempre está no banco. - Auditoria não é observabilidade. Quem alterou o quê fica no banco, com retenção e controle próprios, não num log que expira em 15 dias.
Sistemas internos
- Orçamento pequeno, impacto grande: se o sistema de pedidos para, a operação para.
- O mínimo resolve: erros, uptime e logs centralizados. Cabe num plano gratuito ou num servidor pequeno.
- Uso é um sinal: se o número de usuários ativos cai, pode ser bug, lentidão ou um processo que mudou. Ninguém vai abrir chamado.
- Horário comercial: fora do expediente, só alerta o que realmente para a empresa.
Uma stack por tamanho
| Cenário | Sugestão |
|---|---|
| Sistema interno, um dev | Sentry ou GlitchTip + Uptime Kuma + logs em JSON |
| SaaS no começo | OTel + Sentry + Grafana Cloud (plano grátis) + status page |
| SaaS ou ERP crescendo, sem time de infra | OTel + uma plataforma paga (Datadog, New Relic, Honeycomb ou Grafana Cloud) |
| Volume alto ou dados que não podem sair | OTel Collector + Prometheus/Mimir + Loki + Tempo + Grafana, self-hosted |
| Muitos times, orçamento grande | Plataforma paga com contrato negociado, ou self-hosted com time dedicado |
Em todas as linhas, o OpenTelemetry é a constante: é ele que permite mudar de linha nesta tabela sem reescrever nada.
Checklist
- Erros capturados com stack trace e versão do deploy
- Monitor de uptime externo, fora da sua infraestrutura
- Logs em JSON, centralizados, com
trace_ide sem dados pessoais - RED (taxa, erros, latência p95/p99) nos endpoints principais
- Pelo menos uma métrica de negócio por fluxo crítico
- Heartbeat em todo job agendado
- Latência e erro por integração externa
- Instrumentação com OpenTelemetry, sem SDK proprietário no código
- Nenhum id de usuário ou pedido como label de métrica
- Retenção definida por tipo de dado
- Health checks filtrados
- SLO para os fluxos críticos
- Alertas no sintoma, com dono e runbook
- Revisão mensal de alertas e custos