1. Por que "monitoramento" não é mais suficiente
Por muito tempo, "monitorar" um sistema significava basicamente uma coisa: configurar alguns alertas (CPU alta, disco cheio, processo caiu) e torcer para que eles cubram os problemas que realmente vão acontecer. Isso funciona enquanto o sistema é simples e as formas de falhar são poucas e conhecidas de antemão.
O problema aparece quando o sistema cresce: dezenas de serviços, comunicando-se entre si, rodando em múltiplos containers ou máquinas, com falhas que emergem de combinações imprevisíveis de fatores. Nesse cenário, a pergunta deixa de ser "esse alerta específico disparou?" e passa a ser "por que essa requisição específica ficou lenta, agora, nesse serviço, para esse usuário?" — uma pergunta que ninguém pensou em antecipar com um alerta configurado de antemão.
Observabilidade é a propriedade de um sistema que permite responder a esse tipo de pergunta nova, não prevista, olhando apenas para os dados que ele expõe externamente — sem precisar adicionar instrumentação nova ou fazer deploy de novo código toda vez que surge uma dúvida diferente. Ela se apoia em três tipos de dados, chamados informalmente de "os três pilares": métricas, logs e traces. Esta é a primeira parte de uma série sobre observabilidade que vai construir, artigo a artigo, uma stack completa e funcional com exemplos práticos em Docker Compose.
2. Métricas: números agregados ao longo do tempo
Uma métrica é um valor numérico associado a um timestamp, coletado repetidamente ao longo do tempo — uma série temporal. Exemplos: número de requisições por segundo, uso de memória, tempo de resposta médio, número de erros nos últimos 5 minutos.
Características importantes:
- Baratas de armazenar em volume e por longo prazo — um número por intervalo de tempo ocupa muito menos espaço que um log de texto completo, o que permite guardar meses ou anos de histórico sem custo proibitivo.
- Ótimas para alertas e dashboards — perguntas como "a taxa de erro passou de 5%?" ou "a latência p99 está subindo?" são naturalmente respondidas por métricas.
- Agregadas, não individuais — uma métrica de "tempo de resposta médio" não diz nada sobre qual requisição específica foi lenta, só que, em média, algo mudou. Para investigar o "qual" e o "por quê", é preciso recorrer aos outros dois pilares.
3. Logs: eventos discretos com contexto rico
Um log é um registro textual e datado de um evento específico: uma requisição recebida, um erro capturado, uma conexão de banco aberta. Ao contrário de uma métrica, um log carrega contexto arbitrário — uma mensagem de erro completa, um stack trace, o payload de uma requisição.
Essa riqueza tem um custo: logs são muito mais caros de armazenar e indexar do que métricas, principalmente se cada linha de log for indexada integralmente (busca full-text). É por isso que ferramentas modernas de log, como o Loki (artigo 4 desta série), tomam uma decisão deliberada de indexar só um conjunto pequeno de labels e tratar o conteúdo da linha como texto não indexado — um equilíbrio diferente do Elasticsearch tradicional, que indexa tudo.
4. Traces: o caminho de uma requisição entre serviços
Um trace captura o caminho completo de uma requisição individual à medida que ela atravessa múltiplos serviços — quanto tempo foi gasto em cada etapa, em qual ordem, e onde exatamente uma falha ou lentidão aconteceu. Um trace é composto de spans: cada span representa uma unidade de trabalho (uma chamada HTTP, uma query de banco, uma chamada RPC), com início, fim e metadados.
Enquanto métricas respondem "algo mudou?" e logs respondem "o que aconteceu nesse evento específico?", traces respondem "onde exatamente, entre dez serviços, o tempo está sendo gasto para essa requisição em particular?" — uma pergunta que se torna essencial (e quase impossível de responder sem traces) assim que um sistema deixa de ser um monólito. O artigo 5 desta série cobre OpenTelemetry, o padrão atual para gerar traces.
Requisição do usuário
│
├─ Span: API Gateway (2ms)
│ │
│ └─ Span: Serviço de Pedidos (45ms)
│ │
│ ├─ Span: Query no banco (38ms) ← gargalo aqui
│ └─ Span: Chamada ao Serviço de Estoque (5ms)
5. A stack desta série: Prometheus + Loki + Grafana
Esta série vai construir uma stack de observabilidade mínima, mas funcional, usando três ferramentas open source que se tornaram um padrão de fato:
- Prometheus — coleta e armazena métricas, usando um modelo de "scraping" (ele busca ativamente as métricas de cada aplicação, em vez de esperar que a aplicação as envie). Vem com o PromQL, uma linguagem de consulta específica para séries temporais.
- Loki — agregação de logs, criado pela mesma empresa por trás do Grafana, com uma filosofia deliberada de "indexar como o Prometheus": poucos labels indexados, conteúdo da linha buscado por varredura em tempo de consulta. Isso o torna significativamente mais barato de operar que stacks tradicionais baseadas em Elasticsearch.
- Grafana — a camada de visualização, capaz de consultar tanto Prometheus (PromQL) quanto Loki (LogQL) — e, mais adiante nesta série, também dados de tracing — em dashboards unificados.
Nenhuma das três aparece isolada por acaso: métricas dizem "o quê", logs dizem "por quê" e traces dizem "onde" — e a stack só cumpre seu papel de observabilidade quando as três se completam.
6. Subindo a versão básica com Docker Compose
Para experimentar a stack sem instalar nada localmente além do Docker, um docker-compose.yml mínimo já sobe as três ferramentas:
# docker-compose.yml
services:
prometheus:
image: prom/prometheus:v2.55.0
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
loki:
image: grafana/loki:3.2.0
ports:
- "3100:3100"
grafana:
image: grafana/grafana:11.3.0
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
depends_on:
- prometheus
- loki
O Prometheus precisa de um arquivo de configuração mínimo para não falhar ao subir — por enquanto, só para ele monitorar a si mesmo:
# prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"]
Subindo tudo:
docker compose up -d
- Prometheus fica acessível em
http://localhost:9090— vale abrir e rodar uma query comoupno campo de expressão, que deve retornar1para o próprio Prometheus. - Loki fica acessível em
http://localhost:3100(sem interface visual própria — ele é consultado através do Grafana ou de sua API HTTP). - Grafana fica acessível em
http://localhost:3000(loginadmin/admin, conforme a variável de ambiente definida acima).
Dentro do Grafana, em Connections → Data sources, adicionar o Prometheus (http://prometheus:9090, usando o nome do serviço do Compose como hostname, já que os containers estão na mesma rede) e o Loki (http://loki:3100) como fontes de dados. A partir daqui, a stack está de pé — mas ainda vazia, sem nenhuma aplicação real enviando dados.
7. Conclusão e próximos passos
Vimos o problema que a observabilidade resolve — responder perguntas não antecipadas sobre um sistema em produção —, os papéis complementares de métricas, logs e traces, e subimos a versão mínima da stack desta série: Prometheus, Loki e Grafana rodando via Docker Compose. No próximo artigo, a stack ganha sua primeira fonte de dados real: uma mini aplicação em Python puro que expõe métricas em /metrics, e o Prometheus configurado para fazer scraping delas.
Imagem de capa: Logo oficial do Prometheus — repositório prometheus/prometheus, licença Apache 2.0 (convertido para PNG via wsrv.nl)
Referências:
Top comments (0)