📋 Centralizar logs (Loki / Better Stack)
Logs dispersos em containers individuais são inúteis em pânico. Quando o site cai às 2h da manhã, você quer abrir UMA tela e buscar por "error" nos últimos 15 minutos — não rodar docker logs em 6 containers diferentes.
Duas opções pragmáticas: Loki + Grafana (self-hosted, dá mais trabalho mas tudo seu) ou Better Stack / Logtail (SaaS, 1GB/mês grátis, configura em 5 min). Para um VPS pequeno, comece pelo SaaS.
# Loki via Docker (stack mínimo)
# docker-compose.loki.yml
services:
loki:
image: grafana/loki:2.9.0
ports: ["3100:3100"]
volumes:
- loki-data:/loki
command: -config.file=/etc/loki/local-config.yaml
promtail:
image: grafana/promtail:2.9.0
volumes:
- /var/log:/var/log
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- ./promtail-config.yml:/etc/promtail/config.yml
command: -config.file=/etc/promtail/config.yml
volumes:
loki-data:
💡 Dica prática
Defina retenção desde o dia 1. Logs crescem rápido: 100MB/dia x 90 dias = 9GB. Para Loki, configure retention_period: 720h (30 dias). Para Better Stack, ajuste no painel — o plano grátis retém só 3 dias.
Conceitos-chave
Todos os logs em UM lugar, com busca unificada.
Quantos dias guardar antes de descartar.
Tags (service, env, level) que tornam busca rápida.
Query language para filtrar e agregar logs.
⏱️ Uptime monitor (UptimeRobot grátis)
Se o seu site cai e você descobre pelo cliente, falhou. Um uptime monitor externo bate em endpoints HTTP a cada N minutos e te avisa no segundo em que parar de responder. O UptimeRobot oferece 50 monitores grátis com check de 5 em 5 minutos.
Criar conta e adicionar monitor
Tipo HTTP(s), URL do site, intervalo 5 min. Configure também /api/health para validar dependências, não só o HTML.
Configurar canais de alerta
E-mail (sempre), SMS (pago) ou webhook para Telegram/Slack. Defina quem recebe e em qual horário — alerta de 3h só faz sentido se alguém vai agir.
Publicar status page
Aba "Public Status Pages" gera URL tipo stats.uptimerobot.com/abc123. Sem código, mostra histórico de 90 dias e uptime %.
⚡ Dica prática
Monitor sintético externo (UptimeRobot) e healthcheck interno (Docker) não se substituem. O externo detecta DNS quebrado, certificado expirado, firewall bloqueando — coisas que o container interno acha "ok". Use os dois.
Conceitos-chave
Bate na URL, espera status 2xx em tempo X.
5 min (grátis) ou 1 min (pago) — trade-off custo/latência.
Checks de várias geografias evitam falso-positivo de ISP.
Página pública mostrando histórico de uptime.
📈 Métricas (Prometheus + Grafana)
Logs respondem "o que aconteceu". Métricas respondem "qual a tendência". CPU subiu 30% na última hora? Memória crescendo lentamente desde ontem? Sem métricas você só percebe quando trava. O combo Prometheus (coleta + storage) + Grafana (dashboard) é padrão de mercado.
# docker-compose.monitoring.yml
services:
prometheus:
image: prom/prometheus:latest
ports: ["9090:9090"]
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prom-data:/prometheus
command:
- '--storage.tsdb.retention.time=30d'
- '--config.file=/etc/prometheus/prometheus.yml'
node-exporter:
image: prom/node-exporter:latest
ports: ["9100:9100"]
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
grafana:
image: grafana/grafana:latest
ports: ["3001:3000"]
environment:
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD}
volumes:
- grafana-data:/var/lib/grafana
volumes:
prom-data:
grafana-data:
# prometheus.yml — scrape config mínimo
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ['node-exporter:9100']
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
📊 Dashboards prontos no Grafana
- ID 1860 — Node Exporter Full: CPU, RAM, disco, rede, load average. Importar e plugar — funciona out-of-the-box.
- ID 893 — Docker containers: por container, uso de recursos e status.
- ID 9628 — PostgreSQL: conexões, locks, queries lentas, cache hit ratio.
- Retenção: 30 dias bastam para a maioria. Mais que isso? VictoriaMetrics em vez de Prometheus puro.
Conceitos-chave
Agentes que expõem métricas em /metrics.
Prometheus puxa, não recebe push — mais resiliente.
Linguagem para somar, agregar e calcular métricas.
Time-series DB — guarda séries temporais densas.
🔔 Alertas (e-mail / Telegram)
Métricas que ninguém olha não previnem incidente. Configure Alertmanager (companheiro do Prometheus) para disparar quando CPU passa de 90% por 5 min, disco passa de 85% ou um serviço some. Telegram é o canal mais rápido para alertas pessoais — webhook em 30s.
# alertmanager.yml
route:
receiver: 'telegram'
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receivers:
- name: 'telegram'
telegram_configs:
- bot_token: ${TG_BOT_TOKEN}
chat_id: ${TG_CHAT_ID}
parse_mode: 'HTML'
# rules.yml — regras de alerta
groups:
- name: host
rules:
- alert: HighCPU
expr: 100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 90
for: 5m
labels:
severity: warning
annotations:
summary: "CPU acima de 90% por 5min"
- alert: DiskFull
expr: node_filesystem_avail_bytes / node_filesystem_size_bytes < 0.15
for: 10m
labels:
severity: critical
annotations:
summary: "Disco com menos de 15% livre"
✓ O que FAZER
- ✓Definir
severity(warning / critical) e rotear por canal. - ✓Usar
for: 5mpara evitar disparos por spike momentâneo. - ✓Agrupar alertas (
group_by) para não receber 50 mensagens iguais. - ✓Testar o alerta antes do incidente real — disparo manual.
✗ O que NÃO fazer
- ✗Alertar para tudo — fadiga de alerta mata atenção.
- ✗Disparar critical para CPU em pico de 10s.
- ✗Mandar alerta sem
summaryclaro do que está errado. - ✗Configurar bot do Telegram com token público no repo.
Conceitos-chave
warning (olhar amanhã) vs critical (acordar agora).
HTTP POST que entrega alerta a Telegram/Slack/Discord.
Silenciar alertas durante manutenção planejada.
Doc curto: "se este alerta dispara, faça isto".
🐛 Sentry para erros de app
Logs e métricas mostram sintomas de infra. Sentry mostra exceções da aplicação com stack trace completo, contexto do request, breadcrumbs e quantos usuários foram afetados. Plano grátis: 5k erros/mês — sobra para projeto pequeno.
# Setup em app Node/Next (3 linhas no entry point)
import * as Sentry from "@sentry/node";
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
release: process.env.GIT_SHA,
tracesSampleRate: 0.1, // 10% das requests viram traces
});
# .env
SENTRY_DSN=https://abc123@o12345.ingest.sentry.io/678
GIT_SHA=$(git rev-parse --short HEAD)
🎯 Recursos críticos do Sentry
- DSN: URL única do projeto. Sensível mas não secreta — pode aparecer em frontend (com domain whitelist).
- Source maps: upload no deploy para Sentry traduzir
main.abc123.js:1:8842em arquivo + linha original. - Release tracking: tag
releasemostra qual deploy quebrou — comparar erro antes/depois fica trivial. - Issue grouping: erros similares colapsam em UMA issue com contagem — não 500 e-mails do mesmo bug.
⚠️ Dica prática
Configure beforeSend para scrubbar dados sensíveis (senha, token, cartão) antes do erro sair. Sentry tem PII scrubbing default, mas confiar é arriscado — filtre você mesmo o que sai pela rede.
Conceitos-chave
Endpoint que recebe os erros do seu app.
Mapeiam JS minificado de volta ao código-fonte.
Trilha de ações que precederam o erro.
Tag de versão para isolar regressões.
🌐 Status page pública
Quando algo cai, clientes ligando perguntando "tá fora?" custa mais tempo que o próprio incidente. Uma status page pública resolve: a pessoa abre, vê "Incidente em andamento desde 14:32", e te deixa trabalhar. Uptime Kuma é self-hosted, grátis e bonito.
# Uptime Kuma em 1 comando
docker run -d \
--name uptime-kuma \
--restart unless-stopped \
-p 3002:3001 \
-v uptime-kuma:/app/data \
louislam/uptime-kuma:1
# Acessar em http://servidor:3002
# 1. Criar conta admin
# 2. Adicionar monitores (HTTP, ping, port, DNS, Docker, push)
# 3. Settings > Status Pages > criar pública
# 4. Apontar status.seu-dominio.com via Nginx ou Caddy
📢 Boas práticas de comunicação
- Transparência ganha confiança: esconder incidente é pior que admitir — clientes percebem do mesmo jeito.
- Update a cada 30 min: mesmo sem novidade. "Ainda investigando" é melhor que silêncio.
- Post-mortem público: após resolver, descreva causa raiz e medidas. Cresce credibilidade.
- Subdomínio dedicado:
status.seu-site.comhospedado SEPARADO do app principal — se a infra cai, a status page sobrevive.
✓ O que FAZER
- ✓Hospedar status page em infra diferente do app.
- ✓Mostrar uptime de 90 dias — histórico vira confiança.
- ✓Permitir inscrição por e-mail/RSS para clientes sérios.
- ✓Divulgar a URL no rodapé do site e na docs.
✗ O que NÃO fazer
- ✗Hospedar a status page no mesmo VPS do app.
- ✗Esconder incidentes para "não assustar" — só piora.
- ✗Marcar "all systems operational" sem checar de verdade.
- ✗Esquecer de atualizar quando o incidente termina.
Conceitos-chave
Comunicar incidente cedo, mesmo sem causa-raiz.
Evento com início, updates e resolução documentados.
Metas de disponibilidade (99,9% = 43min/mês fora).
Análise pública do que falhou e como prevenir.
🎯 Resumo do Módulo
/api/health a cada 5 min com alerta multi-canal.for: para evitar fadiga.Próximo Módulo:
6.4 — Backup, restore e plano de disaster recovery