Como monitorar aplicações com Prometheus

1. Introdução ao Prometheus e conceitos fundamentais

Prometheus é um sistema de monitoramento e alerta de código aberto, originalmente desenvolvido pela SoundCloud e atualmente parte da Cloud Native Computing Foundation (CNCF). Sua arquitetura baseada em pull (coleta ativa de métricas) o diferencia de ferramentas tradicionais que utilizam push (agentes enviando dados). O modelo de séries temporais armazena cada métrica como um conjunto de pontos no tempo identificados por labels (pares chave-valor), permitindo consultas flexíveis e agregações poderosas.

Métricas, labels e cardinalidade são conceitos centrais. Uma métrica como http_requests_total pode ter labels method, endpoint e status. A cardinalidade é o número de combinações únicas de labels — se você adicionar um label com valores dinâmicos como user_id, pode causar explosão de séries temporais, sobrecarregando o armazenamento.

Comparado a Zabbix (monitoramento mais tradicional, focado em hosts) ou Datadog/New Relic (SaaS com agentes push), Prometheus oferece maior controle sobre dados, integração nativa com Kubernetes e ecossistema rico de exporters.

2. Instalação e configuração inicial do Prometheus

A forma mais rápida de testar Prometheus é via Docker:

docker run -d --name prometheus -p 9090:9090 prom/prometheus

Para configuração persistente, crie um arquivo prometheus.yml:

global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

Monte o arquivo no container:

docker run -d --name prometheus -p 9090:9090 -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus

No Kubernetes, utilize o operador oficial ou um deployment simples. Acesse a interface web em http://localhost:9090. As páginas /targets mostram o status de cada alvo de coleta, e /graph permite consultas PromQL.

3. Instrumentação de aplicações com client libraries

As client libraries oficiais (Go, Java, Python, Ruby, Rust) expõem métricas em formato texto no endpoint /metrics. Os quatro tipos principais são:

  • Counter: valor que só aumenta (ex: requisições totais)
  • Gauge: valor que pode subir e descer (ex: memória usada)
  • Histogram: distribuição de valores em buckets (ex: latência)
  • Summary: percentis calculados no cliente (ex: latência p99)

Exemplo prático: instrumentar uma API Flask em Python.

Instale a biblioteca:

pip install prometheus-client

Código da aplicação:

from flask import Flask, request
from prometheus_client import Counter, Histogram, generate_latest, REGISTRY
import time

app = Flask(__name__)

REQUESTS = Counter('http_requests_total', 'Total HTTP requests', ['method', 'endpoint', 'status'])
LATENCY = Histogram('http_request_duration_seconds', 'HTTP request latency', ['method', 'endpoint'])

@app.route('/api/health')
def health():
    start = time.time()
    status = 200
    REQUESTS.labels(method='GET', endpoint='/api/health', status=status).inc()
    LATENCY.labels(method='GET', endpoint='/api/health').observe(time.time() - start)
    return 'OK', status

@app.route('/metrics')
def metrics():
    return generate_latest(REGISTRY), 200, {'Content-Type': 'text/plain'}

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Adicione a aplicação como target no prometheus.yml:

scrape_configs:
  - job_name: 'flask_app'
    static_configs:
      - targets: ['localhost:5000']

4. Exporters essenciais para infraestrutura e serviços

Exporters são bridges que expõem métricas de sistemas que não possuem client library nativa.

Node Exporter — Métricas de sistema operacional (CPU, memória, disco, rede):

docker run -d --name node_exporter -p 9100:9100 prom/node-exporter

Blackbox Exporter — Monitoramento de endpoints HTTP, TCP, ICMP:

docker run -d --name blackbox_exporter -p 9115:9115 prom/blackbox-exporter

Configuração no prometheus.yml:

scrape_configs:
  - job_name: 'blackbox_http'
    metrics_path: /probe
    params:
      module: [http_2xx]
    static_configs:
      - targets: ['https://example.com']
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: localhost:9115

Exporters para bancos de dados incluem postgres_exporter, mysqld_exporter, redis_exporter e para message brokers como kafka_exporter.

5. Descoberta de serviços e targets dinâmicos

Em ambientes Kubernetes, o service discovery automático é essencial:

scrape_configs:
  - job_name: 'kubernetes-pods'
    kubernetes_sd_configs:
      - role: pod
    relabel_configs:
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
        action: keep
        regex: true
      - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
        action: replace
        regex: ([^:]+)(?::\d+)?;(\d+)
        replacement: $1:$2
        target_label: __address__

Para ambientes estáticos, use file_sd_configs:

scrape_configs:
  - job_name: 'custom_services'
    file_sd_configs:
      - files: ['/etc/prometheus/targets/*.json']

Arquivo JSON de exemplo:

[
  {"targets": ["192.168.1.10:9100", "192.168.1.11:9100"], "labels": {"env": "production"}}
]

relabel_configs e metric_relabel_configs permitem filtrar, renomear e modificar labels antes do armazenamento.

6. Consultas com PromQL para análise de métricas

PromQL (Prometheus Query Language) é a linguagem de consulta. Exemplos práticos:

Taxa de requisições por segundo:

rate(http_requests_total[5m])

Latência média dos últimos 10 minutos:

avg(rate(http_request_duration_seconds_sum[10m]) / rate(http_request_duration_seconds_count[10m]))

Percentil 99 de latência:

histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))

Uso de CPU por instância:

100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

Regras de gravação para otimizar consultas complexas:

groups:
  - name: recording_rules
    rules:
      - record: job:http_requests:rate5m
        expr: rate(http_requests_total[5m])

7. Alertas com Alertmanager e integrações

Defina regras de alerta no prometheus.yml:

rule_files:
  - 'alerts.yml'

Arquivo alerts.yml:

groups:
  - name: instance_alerts
    rules:
      - alert: InstanceDown
        expr: up == 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Instance {{ $labels.instance }} down"
          description: "Instance {{ $labels.instance }} has been down for more than 5 minutes."

Configure o Alertmanager (alertmanager.yml):

route:
  receiver: 'slack'
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h

receivers:
  - name: 'slack'
    slack_configs:
      - api_url: 'https://hooks.slack.com/services/TOKEN'
        channel: '#alerts'

Integrações com PagerDuty, e-mail e webhooks seguem padrão similar.

8. Boas práticas e otimização de desempenho

Gerenciamento de cardinalidade: evite labels com valores ilimitados (user IDs, e-mails). Use labels como method, status, endpoint que têm valores previsíveis.

Retenção de dados: por padrão, Prometheus retém 15 dias localmente. Para períodos maiores, use armazenamento remoto como Thanos ou Cortex:

--storage.tsdb.retention.time=30d

Estratégias de scrape: ajuste scrape_interval conforme a criticidade. Métricas de infraestrutura podem usar 15s; métricas de negócio, 30s ou mais.

Otimização: evite consultas sem intervalos de tempo (ex: http_requests_total sem [5m]), use recording rules para consultas frequentes e monitore o próprio Prometheus com métricas como prometheus_target_interval_length_seconds.

Referências