Observabilidade total: métricas, logs e alertas com Prometheus e Grafana

Observabilidade total: métricas, logs e alertas com Prometheus e Grafana
Resumo: Este artigo apresenta, de forma prática e detalhada, como montar uma stack de observabilidade usando Prometheus, Grafana e Alertmanager. Você aprenderá a coletar métricas, centralizar logs estruturados, criar dashboards interativos e configurar alertas inteligentes que reduzem o MTTR (Mean Time To Recovery) das suas aplicações.
Introdução
Em ambientes de produção modernos, a simples monitoração de disponibilidade já não é suficiente. Equipes de SRE e desenvolvedores precisam de observabilidade – a capacidade de entender o que está acontecendo dentro de um sistema a partir de seus sinais externos (métricas, logs e rastreamentos). Quando bem implementada, a observabilidade permite:
Detecção precoce de anomalias antes que usuários finais percebam o problema. Diagnóstico rápido, reduzindo o tempo de investigação. Feedback contínuo para melhorar a arquitetura e o código.
Neste artigo, vamos montar uma solução completa baseada em ferramentas open source amplamente adotadas no mercado: Prometheus para coleta de métricas, Grafana para visualização e Alertmanager para orquestração de alertas. Também abordaremos a ingestão de logs estruturados usando Loki, o parceiro de logs da Grafana Labs, garantindo que métricas e logs estejam disponíveis no mesmo painel.
Dica: Se ainda não tem nenhum dos componentes instalados, recomendamos usar o Docker Compose apresentado ao final para levantar tudo em poucos minutos.
1. Conceitos fundamentais de observabilidade
Antes de mergulharmos na prática, vale reforçar três pilares que sustentam a observabilidade:
| Pilar | O que é | Por que importa |
|---|---|---|
| Métricas | Valores numéricos ao longo do tempo (ex.: latência, taxa de erro). | Permitem detectar tendências e disparar alertas baseados em limites. |
| Logs estruturados | Texto em formato JSON ou similar, contendo chaves e valores. | Facilitam a correlação de eventos e a busca avançada. |
| Rastreamentos (opcional) | Cadeia de chamadas distribuídas entre serviços. | Ajudam a identificar gargalos em arquiteturas complexas. |
Neste tutorial focaremos nos dois primeiros, que já são suficientes para cobrir a maioria dos casos de uso em sistemas web e APIs.
2. Coletando métricas com Prometheus
2.1 O que é o Prometheus?
Prometheus é um time‑series database (TSDB) que coleta métricas via HTTP em um formato chamado exposição. Ele funciona no modelo pull: periodicamente, o servidor Prometheus faz requisições a endpoints /metrics dos alvos configurados.
2.2 Configurando o Prometheus
Crie um diretório chamado observability e dentro dele um arquivo prometheus.yml:
# prometheus.yml
global:
scrape_interval: 15s # frequência padrão de coleta
evaluation_interval: 15s # frequência de avaliação de regras
scrape_configs:
# 1️⃣ Alvo da aplicação Node.js (exemplo abaixo)
- job_name: 'node_app'
static_configs:
- targets: ['host.docker.internal:9100']
# 2️⃣ Exporter do sistema (cAdvisor) para métricas de containers
- job_name: 'cadvisor'
static_configs:
- targets: ['cadvisor:8080']
# 3️⃣ Exporter do Loki para métricas de ingestão de logs
- job_name: 'loki'
static_configs:
- targets: ['loki:3100']
Observação:
host.docker.internalpermite que o container do Prometheus acesse o host local (útil para desenvolvimento).
2.3 Expondo métricas em uma aplicação Node.js
Instale o cliente oficial:
npm install prom-client
Em seguida, adicione o seguinte código ao seu servidor Express:
// metrics.js
const client = require('prom-client');
const express = require('express');
const app = express();
// Cria um Registry padrão
const register = new client.Registry();
// Métrica de contagem de requisições HTTP
const httpRequestsTotal = new client.Counter({
name: 'http_requests_total',
help: 'Total de requisições HTTP recebidas',
labelNames: ['method', 'route', 'code'],
});
// Métrica de latência (histograma)
const httpRequestDuration = new client.Histogram({
name: 'http_request_duration_seconds',
help: 'Duração das requisições HTTP em segundos',
labelNames: ['method', 'route', 'code'],
buckets: [0.05, 0.1, 0.3, 0.5, 1, 3, 5],
});
register.registerMetric(httpRequestsTotal);
register.registerMetric(httpRequestDuration);
client.collectDefaultMetrics({ register });
app.use((req, res, next) => {
const end = httpRequestDuration.startTimer();
res.on('finish', () => {
httpRequestsTotal.inc({ method: req.method, route: req.path, code: res.statusCode });
end({ method: req.method, route: req.path, code: res.statusCode });
});
next();
});
// Endpoint de métricas
app.get('/metrics', async (req, res) => {
res.set('Content-Type', register.contentType);
res.end(await register.metrics());
});
module.exports = app;
Integre ao seu server.js:
// server.js
const http = require('http');
const app = require('./metrics');
const server = http.createServer(app);
server.listen(9100, () => {
console.log('Servidor rodando em http://localhost:9100');
});
Agora, ao iniciar a aplicação, o Prometheus conseguirá coletar as métricas em http://localhost:9100/metrics.
2.4 Regras de gravação (recording rules)
Para evitar cálculos pesados em tempo real, podemos pré‑agregar métricas:
# rules.yml
groups:
- name: latency_rules
interval: 30s
rules:
- record: job:http_request_duration_seconds:avg_5m
expr: avg_over_time(http_request_duration_seconds[5m])
Inclua o arquivo nas rule_files do prometheus.yml:
rule_files:
- "rules.yml"
3. Centralizando logs com Loki e Grafana
3.1 Por que Loki?
Loki foi projetado para ser compatível com Prometheus: as mesmas labels usadas nas métricas podem ser reutilizadas nos logs, facilitando a correlação. Diferente de soluções de busca genéricas, Loki armazena apenas os metadados (labels) e delega o conteúdo dos logs a um armazenamento de objetos (ex.: S3, MinIO).
3.2 Configurando Loki via Docker Compose
# docker-compose.yml (trecho)
services:
loki:
image: grafana/loki:2.9.1
command: -config.file=/etc/loki/local-config.yaml
ports:
- "3100:3100"
volumes:
- ./loki-config.yaml:/etc/loki/local-config.yaml
promtail:
image: grafana/promtail:2.9.1
volumes:
- /var/log:/var/log
- ./promtail-config.yaml:/etc/promtail/config.yaml
command: -config.file=/etc/promtail/config.yaml
promtail-config.yaml – agente que envia logs para o Loki:
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
__path__: /var/log//.log
3.3 Logs estruturados na aplicação Node.js
Modifique o código para usar pino, que já gera JSON:
npm install pino pino-http
// logger.js
const pino = require('pino');
const logger = pino({
level: 'info',
base: { pid: process.pid },
timestamp: () => ,"time":"${new Date().toISOString()}",
});
module.exports = logger;
Integre ao Express:
// server.js (continuação)
const logger = require('./logger');
app.use(require('pino-http')({ logger }));
app.get('/hello', (req, res) => {
logger.info({ route: '/hello', method: req.method }, 'Endpoint acessado');
res.send('Olá Mundo!');
});
Agora, os logs são enviados ao stdout em formato JSON. O promtail captura o stdout (se configurado) ou arquivos de log e os encaminha ao Loki.
3.4 Visualizando métricas e logs no Grafana
Instale o Grafana via Docker:
```yaml grafana: image: grafana/grafana:10.2.0 ports: - "3000:3000" environment: - GF_SECURITY_ADMIN_PASSWORD=admin volumes: - grafana-data:/var/lib/grafana


