<h2>Introdução ao Prometheus: Por que Monitorar?</h2>
<p>Quando você trabalha com sistemas em produção, é fundamental saber o que está acontecendo em tempo real. O Prometheus é uma ferramenta de código aberto que coleta, armazena e permite consultar métricas de seus aplicativos e infraestrutura. Diferentemente de ferramentas antigas que dependiam de agentes push (enviando dados), o Prometheus utiliza um modelo pull (buscando dados), o que oferece maior controle, resiliência e simplicidade operacional.</p>
<p>A arquitetura do Prometheus é composta por alguns componentes principais: o servidor Prometheus (que scrapa métricas), o Alertmanager (que gerencia alertas), o Node Exporter (que fornece métricas do sistema) e ferramentas de visualização como Grafana. Neste artigo, você aprenderá como configurar o Prometheus, escrever consultas em PromQL e implementar um sistema robusto de alertas.</p>
<h2>Coleta de Métricas com Prometheus</h2>
<h3>Como o Prometheus Funciona</h3>
<p>O Prometheus opera em um modelo simples: em intervalos regulares (definidos em sua configuração), ele acessa um endpoint HTTP (chamado <code>/metrics</code>) em cada aplicação monitorada e coleta as métricas expostas em formato texto. Essas métricas são armazenadas localmente no disco em um formato otimizado de série temporal. Esse modelo pull oferece vantagens significativas: você tem controle sobre quando os dados são coletados, os aplicativos não precisam conhecer sobre o Prometheus, e a ferramenta é mais resiliente a falhas temporárias de rede.</p>
<p>As métricas no Prometheus seguem uma nomenclatura específica. Cada métrica tem um nome (como <code>http_requests_total</code>) e pode ter múltiplas labels (dimensões) como <code>method="GET"</code> ou <code>status="200"</code>. Existem quatro tipos de métricas: Counter (aumenta monotonicamente), Gauge (pode subir ou descer), Histogram (distribui em buckets) e Summary (fornece quantis).</p>
<h3>Instalando e Configurando o Prometheus</h3>
<p>Para começar, você precisa baixar e configurar o Prometheus. Crie um arquivo <code>prometheus.yml</code>:</p>
<pre><code class="language-yaml">global:
scrape_interval: 15s
evaluation_interval: 15s
alerting:
alertmanagers:
- static_configs:
- targets: ['localhost:9093']
rule_files:
- 'alerts.yml'
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node'
static_configs:
- targets: ['localhost:9100']
- job_name: 'app'
static_configs:
- targets: ['localhost:8080']</code></pre>
<p>Este arquivo define que o Prometheus coletará métricas a cada 15 segundos de três fontes: ele mesmo, um Node Exporter na porta 9100 e sua aplicação na porta 8080. Você pode iniciar o Prometheus com:</p>
<pre><code class="language-bash">./prometheus --config.file=prometheus.yml</code></pre>
<h3>Instrumentando sua Aplicação</h3>
<p>Para que sua aplicação exponha métricas, você precisa usar uma biblioteca cliente. Aqui está um exemplo com Python usando a biblioteca <code>prometheus_client</code>:</p>
<pre><code class="language-python">from prometheus_client import Counter, Gauge, Histogram, start_http_server
import time
import random
Definir métricas
request_count = Counter(
'http_requests_total',
'Total de requisições HTTP',
['method', 'endpoint', 'status']
)
request_duration = Histogram(
'http_request_duration_seconds',
'Duração das requisições em segundos',
['method', 'endpoint']
)
active_connections = Gauge(
'active_connections',
'Número de conexões ativas'
)
Iniciar servidor HTTP na porta 8080
start_http_server(8080)
Simular requisições
while True:
method = random.choice(['GET', 'POST', 'DELETE'])
endpoint = random.choice(['/users', '/products', '/orders'])
status = random.choice([200, 201, 400, 500])
duration = random.uniform(0.1, 2.0)
request_count.labels(method=method, endpoint=endpoint, status=status).inc()
request_duration.labels(method=method, endpoint=endpoint).observe(duration)
active_connections.set(random.randint(10, 100))
time.sleep(1)</code></pre>
<p>Ao rodar este script, sua aplicação expõe métricas em <code>http://localhost:8080/metrics</code>. O Prometheus coletará automaticamente esses dados de acordo com a configuração.</p>
<h2>PromQL: A Linguagem de Consulta do Prometheus</h2>
<h3>Fundamentos da PromQL</h3>
<p>PromQL (Prometheus Query Language) é uma linguagem poderosa e expressiva para consultar dados de série temporal. Diferentemente do SQL, ela foi projetada especificamente para trabalhar com métricas temporais. Uma consulta PromQL simples retorna o valor atual de uma métrica, mas sua verdadeira força reside em funções de agregação, transformação e análise temporal.</p>
<p>A sintaxe básica é intuitiva: você começa com o nome da métrica seguido de filtros entre chaves. Por exemplo, <code>http_requests_total{method="GET"}</code> retorna todas as métricas com nome <code>http_requests_total</code> que possuem o label <code>method</code> com valor <code>GET</code>.</p>
<h3>Consultando Métricas Básicas</h3>
<p>Aqui estão exemplos de consultas fundamentais que você usará constantemente:</p>
<pre><code class="language-promql"># Retorna o valor atual de uma métrica
http_requests_total
Filtra por um label específico
http_requests_total{method="GET"}
Filtra por múltiplos labels
http_requests_total{method="GET", status="200"}
Usa operadores de regex para filtrar
http_requests_total{endpoint=~"/users.*"}
Exclui valores com um operador negativo
http_requests_total{status!="200"}</code></pre>
<p>Essas consultas retornam séries temporais instantâneas. Para análises mais úteis, você precisa de funções que operam sobre períodos de tempo.</p>
<h3>Funções e Operações Temporais</h3>
<p>As funções mais importantes no PromQL trabalham com períodos de tempo (ranges). A sintaxe <code>[5m]</code> significa "últimos 5 minutos". Confira os exemplos práticos:</p>
<pre><code class="language-promql"># Taxa de aumento por segundo nos últimos 5 minutos
rate(http_requests_total[5m])
Aumento absoluto nos últimos 10 minutos
increase(http_requests_total[10m])
Valor máximo nos últimos 1 hora
max_over_time(http_request_duration_seconds[1h])
Valor mínimo nos últimos 30 minutos
min_over_time(http_request_duration_seconds[30m])
Média de uma métrica nos últimos 5 minutos
avg(rate(http_requests_total[5m]))
Soma de uma métrica agrupada por método
sum(rate(http_requests_total[5m])) by (method)
Percentil 95 de duração de requisições
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))</code></pre>
<p>A função <code>rate()</code> é particularmente importante: ela calcula a taxa de mudança por segundo, ideal para counters que crescem continuamente. Para uma requisição que levou 2 segundos, você usaria <code>increase()</code> para saber quanto a métrica cresceu em um período, enquanto <code>rate()</code> já converte para unidade por segundo.</p>
<h3>Agregações e Combinações Complexas</h3>
<p>Quando você tem múltiplas instâncias ou endpoints, precisa agregar dados de forma inteligente:</p>
<pre><code class="language-promql"># Soma de requisições por método (agrupação)
sum(http_requests_total) by (method)
Quantidade de instâncias com taxa de erro acima de 1%
count(rate(http_requests_total{status=~"5.."}[5m]) > 0.01)
Requisições por segundo por endpoint e método
sum(rate(http_requests_total[5m])) by (endpoint, method)
Taxa de erro percentual
(sum(rate(http_requests_total{status=~"5.."}[5m])) by (endpoint) /
sum(rate(http_requests_total[5m])) by (endpoint)) * 100
Instâncias que não tiveram scrape bem-sucedido nos últimos 5 minutos
up{job="app"} == 0</code></pre>
<p>A consulta de taxa de erro mostra como combinar múltiplas consultas com operadores aritméticos. O resultado é uma porcentagem de requisições que falharam, extremamente útil para alertas.</p>
<h2>Alertmanager: Gerenciando Alertas</h2>
<h3>Arquitetura e Conceitos de Alertas</h3>
<p>O Alertmanager é o componente responsável por gerenciar alertas gerados pelo Prometheus. Ele recebe alertas da regra de avaliação do Prometheus, agrupa-os, deduplica-os e roteia-os para seus destinos finais (email, Slack, PagerDuty, etc.). Um ponto crítico que muitos iniciantes não entendem: o Prometheus e Alertmanager são separados. O Prometheus avalia as regras, o Alertmanager entrega as notificações.</p>
<p>Existem conceitos importantes a entender: um alert tem estados (firing, pending, inactive), pode ser silenciado temporariamente e pode ser roteado para diferentes receptores com base em seus labels. Isso permite que um alerta crítico vá para PagerDuty enquanto um aviso vai apenas para o Slack.</p>
<h3>Definindo Regras de Alerta</h3>
<p>No arquivo <code>alerts.yml</code>, você define quando um alerta deve disparar. Aqui está um exemplo funcional:</p>
<pre><code class="language-yaml">groups:
- name: application_alerts
interval: 30s
rules:
- alert: HighErrorRate
expr: |
(sum(rate(http_requests_total{status=~"5.."}[5m])) by (job) /
sum(rate(http_requests_total[5m])) by (job)) > 0.05
for: 5m
labels:
severity: critical
team: backend
annotations:
summary: "Taxa de erro alta em {{ $labels.job }}"
description: A aplicação {{ $labels.job }} tem taxa de erro de {{ $value | humanizePercentage }}
nos últimos 5 minutos.
- alert: ServiceDown
expr: up{job="app"} == 0
for: 2m
labels:
severity: critical
annotations:
summary: "Serviço {{ $labels.job }} está down"
description: "A instância {{ $labels.instance }} está inativa há mais de 2 minutos"
- alert: HighMemoryUsage
expr: (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) < 0.15
for: 10m
labels:
severity: warning
annotations:
summary: "Uso de memória alto no servidor {{ $labels.instance }}"
description: "Menos de 15% de memória disponível"
- alert: SlowRequests
expr: |
histogram_quantile(0.95,
sum(rate(http_request_duration_seconds_bucket[5m])) by (endpoint, le)
) > 1
for: 5m
labels:
severity: warning
annotations:
summary: "Requisições lentas em {{ $labels.endpoint }}"
description: "P95 de latência está acima de 1 segundo"</code></pre>
<p>Cada regra tem uma expressão PromQL (<code>expr</code>), uma duração antes de disparar (<code>for</code>), labels para categorizar o alerta e anotações para fornecer contexto. O parâmetro <code>for</code> é crucial: garante que o alerta só dispare se a condição persistir por esse período, evitando alertas por espikes temporários.</p>
<h3>Configurando o Alertmanager</h3>
<p>O Alertmanager precisa estar rodando e configurado para receber alertas do Prometheus. Crie um arquivo <code>alertmanager.yml</code>:</p>
<pre><code class="language-yaml">global:
resolve_timeout: 5m
slack_api_url: 'YOUR_SLACK_WEBHOOK_URL'
route:
receiver: 'default'
group_by: ['alertname', 'cluster', 'service']
group_wait: 10s
group_interval: 10s
repeat_interval: 12h
routes:
- match:
severity: critical
receiver: 'pagerduty'
continue: true
- match:
severity: warning
receiver: 'slack'
receivers:
- name: 'default'
slack_configs:
- channel: '#alerts'
title: 'Alerta Prometheus'
text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
- name: 'pagerduty'
pagerduty_configs:
- service_key: 'YOUR_PAGERDUTY_SERVICE_KEY'
description: '{{ .GroupLabels.alertname }}'
- name: 'slack'
slack_configs:
- channel: '#warnings'
text: '{{ .GroupLabels.alertname }}: {{ .Alerts.Firing | len }} alertas'
inhibit_rules:
- source_match:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['alertname', 'dev', 'instance']</code></pre>
<p>Este arquivo define como os alertas são roteados. O <code>route</code> principal menciona que alertas críticos vão para PagerDuty enquanto avisos vão para Slack. A seção <code>inhibit_rules</code> evita notificações duplicadas: se um alerta crítico está ativo, alertas de warning relacionados são suprimidos. Inicie o Alertmanager com:</p>
<pre><code class="language-bash">./alertmanager --config.file=alertmanager.yml</code></pre>
<h3>Exemplos Práticos de Alertas Bem Projetados</h3>
<p>Um alerta bem projetado não gera ruído desnecessário. Aqui está um exemplo de um alerta robusto para timeout em operações de banco de dados:</p>
<pre><code class="language-yaml">- alert: DatabaseQueryTimeout
expr: |
rate(db_query_timeout_total[5m]) > 0.1
for: 10m
labels:
severity: warning
team: database
annotations:
summary: "Timeouts de banco de dados detectados em {{ $labels.database }}"
description: O banco de dados {{ $labels.database }} está tendo {{ $value | humanize }}
timeouts por segundo nos últimos 5 minutos.
Possíveis causas:
- Carga de I/O alta no servidor
- Queries lentas ou locks de tabela
- Recursos de CPU/memória insuficientes
Ação recomendada: Verificar logs do banco de dados e executar EXPLAIN nas queries lentas.</code></pre>
<p>Este alerta combina várias boas práticas: usa <code>for</code> de 10 minutos para evitar alertas temporários, fornece contexto específico no <code>summary</code>, explica possíveis causas e até sugere ações. As anotações aparecem nos alertas notificados, ajudando o time a resolver rapidamente.</p>
<h2>Integração Completa: Exemplo Prático End-to-End</h2>
<p>Para consolidar o aprendizado, aqui está um exemplo completo de monitoramento. Suponha que você tem uma API de processamento de pedidos. Primeiro, crie a aplicação em Python com métricas:</p>
<pre><code class="language-python">from prometheus_client import Counter, Histogram, Gauge, start_http_server
from flask import Flask, request
import time
import random
app = Flask(__name__)
start_http_server(8080)
Métricas
request_duration = Histogram(
'order_api_duration_seconds',
'Duração do processamento',
['endpoint', 'method'],
buckets=(0.1, 0.5, 1.0, 2.0, 5.0)
)
requests_total = Counter(
'order_api_requests_total',
'Total de requisições',
['endpoint', 'method', 'status']
)
orders_processed = Counter(
'orders_processed_total',
'Total de pedidos processados',
['status']
)
processing_queue_size = Gauge(
'processing_queue_size',
'Tamanho da fila de processamento'
)
@app.route('/orders', methods=['POST'])
def create_order():
start = time.time()
try:
Simula processamento
duration = random.uniform(0.1, 2.0)
time.sleep(duration)
Simulação: 5% de falha
if random.random() < 0.05:
requests_total.labels(
endpoint='/orders', method='POST', status=500
).inc()
orders_processed.labels(status='failed').inc()
return {'error': 'Processing failed'}, 500
requests_total.labels(
endpoint='/orders', method='POST', status=201
).inc()
orders_processed.labels(status='success').inc()
return {'order_id': 123}, 201
finally:
request_duration.labels(
endpoint='/orders', method='POST'
).observe(time.time() - start)
processing_queue_size.set(random.randint(5, 50))
if __name__ == '__main__':
app.run(port=5000, debug=False)</code></pre>
<p>Configure o arquivo <code>prometheus.yml</code> para coletar da aplicação:</p>
<pre><code class="language-yaml">global:
scrape_interval: 15s
alerting:
alertmanagers:
- static_configs:
- targets: ['localhost:9093']
rule_files:
- 'alerts.yml'
scrape_configs:
- job_name: 'order_api'
static_configs:
- targets: ['localhost:8080']</code></pre>
<p>E defina alertas relevantes em <code>alerts.yml</code>:</p>
<pre><code class="language-yaml">groups:
- name: order_system
rules:
- alert: OrderProcessingErrorRate
expr: |
(sum(rate(order_api_requests_total{status="500"}[5m])) /
sum(rate(order_api_requests_total[5m]))) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "Taxa de erro em processamento de pedidos acima de 5%"
- alert: SlowOrderProcessing
expr: |
histogram_quantile(0.95,
sum(rate(order_api_duration_seconds_bucket[5m])) by (le)
) > 2
for: 10m
labels:
severity: warning
annotations:
summary: "Processamento de pedidos está lento"
- alert: QueueBuildup
expr: processing_queue_size > 100
for: 5m
labels:
severity: warning
annotations:
summary: "Fila de processamento acumulando"</code></pre>
<p>Com essa configuração, você tem monitoramento completo: coleta de métricas da aplicação, consultas em PromQL para análise e alertas automáticos para situações anormais.</p>
<h2>Conclusão</h2>
<p>Você aprendeu três conceitos fundamentais para monitoramento profissional. Primeiro, como o Prometheus coleta métricas via modelo pull de aplicações instrumentadas, oferecendo simplicidade e resiliência superior a ferramentas antigas. Segundo, como usar PromQL para consultar dados de série temporal com funções como <code>rate()</code> e <code>histogram_quantile()</code>, transformando métricas brutas em insights acionáveis. Terceiro, como configurar o Alertmanager para rotear alertas de forma inteligente, evitando ruído ao mesmo tempo em que garante que problemas críticos sejam notificados imediatamente.</p>
<p>O verdadeiro domínio vem da prática: configure o Prometheus em seu próprio projeto, experimente diferentes PromQL queries no dashboard, e ajuste suas regras de alerta com base no feedback operacional. Lembre-se que um bom alerta é aquele que dispara apenas quando há ação a tomar — não aquele que notifica constantemente sobre problemas que você não pode resolver.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://prometheus.io/docs/introduction/overview/" target="_blank" rel="noopener noreferrer">Documentação Oficial do Prometheus</a></li>
<li><a href="https://prometheus.io/docs/prometheus/latest/querying/basics/" target="_blank" rel="noopener noreferrer">Prometheus Query Language Documentation</a></li>
<li><a href="https://prometheus.io/docs/alerting/latest/overview/" target="_blank" rel="noopener noreferrer">Alertmanager Documentation</a></li>
<li><a href="https://prometheus.io/docs/practices/instrumentation/" target="_blank" rel="noopener noreferrer">Prometheus Best Practices Guide</a></li>
<li><a href="https://kubernetes.io/docs/tasks/debug-application-cluster/resource-metrics-pipeline/" target="_blank" rel="noopener noreferrer">Kubernetes Monitoring with Prometheus</a></li>
</ul>
<p><!-- FIM --></p>