DevOps & CI/CD

O que Todo Dev Deve Saber sobre Prometheus: Coleta de Métricas, PromQL e Alertmanager

17 min de leitura

O que Todo Dev Deve Saber sobre Prometheus: Coleta de Métricas, PromQL e Alertmanager

Introdução ao Prometheus: Por que Monitorar? 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. 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. Coleta de Métricas com Prometheus Como o Prometheus Funciona O Prometheus opera em um modelo simples: em intervalos regulares (definidos em sua configuração), ele acessa um endpoint HTTP (chamado ) em cada aplicação monitorada e

<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=&quot;GET&quot;</code> ou <code>status=&quot;200&quot;</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: [&#039;localhost:9093&#039;]

rule_files:

  • &#039;alerts.yml&#039;

scrape_configs:

  • job_name: &#039;prometheus&#039;

static_configs:

  • targets: [&#039;localhost:9090&#039;]
  • job_name: &#039;node&#039;

static_configs:

  • targets: [&#039;localhost:9100&#039;]
  • job_name: &#039;app&#039;

static_configs:

  • targets: [&#039;localhost:8080&#039;]</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(

&#039;http_requests_total&#039;,

&#039;Total de requisições HTTP&#039;,

[&#039;method&#039;, &#039;endpoint&#039;, &#039;status&#039;]

)

request_duration = Histogram(

&#039;http_request_duration_seconds&#039;,

&#039;Duração das requisições em segundos&#039;,

[&#039;method&#039;, &#039;endpoint&#039;]

)

active_connections = Gauge(

&#039;active_connections&#039;,

&#039;Número de conexões ativas&#039;

)

Iniciar servidor HTTP na porta 8080

start_http_server(8080)

Simular requisições

while True:

method = random.choice([&#039;GET&#039;, &#039;POST&#039;, &#039;DELETE&#039;])

endpoint = random.choice([&#039;/users&#039;, &#039;/products&#039;, &#039;/orders&#039;])

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=&quot;GET&quot;}</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=&quot;GET&quot;}

Filtra por múltiplos labels

http_requests_total{method=&quot;GET&quot;, status=&quot;200&quot;}

Usa operadores de regex para filtrar

http_requests_total{endpoint=~&quot;/users.*&quot;}

Exclui valores com um operador negativo

http_requests_total{status!=&quot;200&quot;}</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 &quot;últimos 5 minutos&quot;. 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=~&quot;5..&quot;}[5m]) &gt; 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=~&quot;5..&quot;}[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=&quot;app&quot;} == 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=~&quot;5..&quot;}[5m])) by (job) /

sum(rate(http_requests_total[5m])) by (job)) &gt; 0.05

for: 5m

labels:

severity: critical

team: backend

annotations:

summary: &quot;Taxa de erro alta em {{ $labels.job }}&quot;

description: A aplicação {{ $labels.job }} tem taxa de erro de {{ $value | humanizePercentage }}

nos últimos 5 minutos.

  • alert: ServiceDown

expr: up{job=&quot;app&quot;} == 0

for: 2m

labels:

severity: critical

annotations:

summary: &quot;Serviço {{ $labels.job }} está down&quot;

description: &quot;A instância {{ $labels.instance }} está inativa há mais de 2 minutos&quot;

  • alert: HighMemoryUsage

expr: (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) &lt; 0.15

for: 10m

labels:

severity: warning

annotations:

summary: &quot;Uso de memória alto no servidor {{ $labels.instance }}&quot;

description: &quot;Menos de 15% de memória disponível&quot;

  • alert: SlowRequests

expr: |

histogram_quantile(0.95,

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

) &gt; 1

for: 5m

labels:

severity: warning

annotations:

summary: &quot;Requisições lentas em {{ $labels.endpoint }}&quot;

description: &quot;P95 de latência está acima de 1 segundo&quot;</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: &#039;YOUR_SLACK_WEBHOOK_URL&#039;

route:

receiver: &#039;default&#039;

group_by: [&#039;alertname&#039;, &#039;cluster&#039;, &#039;service&#039;]

group_wait: 10s

group_interval: 10s

repeat_interval: 12h

routes:

  • match:

severity: critical

receiver: &#039;pagerduty&#039;

continue: true

  • match:

severity: warning

receiver: &#039;slack&#039;

receivers:

  • name: &#039;default&#039;

slack_configs:

  • channel: &#039;#alerts&#039;

title: &#039;Alerta Prometheus&#039;

text: &#039;{{ range .Alerts }}{{ .Annotations.description }}{{ end }}&#039;

  • name: &#039;pagerduty&#039;

pagerduty_configs:

  • service_key: &#039;YOUR_PAGERDUTY_SERVICE_KEY&#039;

description: &#039;{{ .GroupLabels.alertname }}&#039;

  • name: &#039;slack&#039;

slack_configs:

  • channel: &#039;#warnings&#039;

text: &#039;{{ .GroupLabels.alertname }}: {{ .Alerts.Firing | len }} alertas&#039;

inhibit_rules:

  • source_match:

severity: &#039;critical&#039;

target_match:

severity: &#039;warning&#039;

equal: [&#039;alertname&#039;, &#039;dev&#039;, &#039;instance&#039;]</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]) &gt; 0.1

for: 10m

labels:

severity: warning

team: database

annotations:

summary: &quot;Timeouts de banco de dados detectados em {{ $labels.database }}&quot;

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(

&#039;order_api_duration_seconds&#039;,

&#039;Duração do processamento&#039;,

[&#039;endpoint&#039;, &#039;method&#039;],

buckets=(0.1, 0.5, 1.0, 2.0, 5.0)

)

requests_total = Counter(

&#039;order_api_requests_total&#039;,

&#039;Total de requisições&#039;,

[&#039;endpoint&#039;, &#039;method&#039;, &#039;status&#039;]

)

orders_processed = Counter(

&#039;orders_processed_total&#039;,

&#039;Total de pedidos processados&#039;,

[&#039;status&#039;]

)

processing_queue_size = Gauge(

&#039;processing_queue_size&#039;,

&#039;Tamanho da fila de processamento&#039;

)

@app.route(&#039;/orders&#039;, methods=[&#039;POST&#039;])

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() &lt; 0.05:

requests_total.labels(

endpoint=&#039;/orders&#039;, method=&#039;POST&#039;, status=500

).inc()

orders_processed.labels(status=&#039;failed&#039;).inc()

return {&#039;error&#039;: &#039;Processing failed&#039;}, 500

requests_total.labels(

endpoint=&#039;/orders&#039;, method=&#039;POST&#039;, status=201

).inc()

orders_processed.labels(status=&#039;success&#039;).inc()

return {&#039;order_id&#039;: 123}, 201

finally:

request_duration.labels(

endpoint=&#039;/orders&#039;, method=&#039;POST&#039;

).observe(time.time() - start)

processing_queue_size.set(random.randint(5, 50))

if __name__ == &#039;__main__&#039;:

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: [&#039;localhost:9093&#039;]

rule_files:

  • &#039;alerts.yml&#039;

scrape_configs:

  • job_name: &#039;order_api&#039;

static_configs:

  • targets: [&#039;localhost:8080&#039;]</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=&quot;500&quot;}[5m])) /

sum(rate(order_api_requests_total[5m]))) &gt; 0.05

for: 5m

labels:

severity: critical

annotations:

summary: &quot;Taxa de erro em processamento de pedidos acima de 5%&quot;

  • alert: SlowOrderProcessing

expr: |

histogram_quantile(0.95,

sum(rate(order_api_duration_seconds_bucket[5m])) by (le)

) &gt; 2

for: 10m

labels:

severity: warning

annotations:

summary: &quot;Processamento de pedidos está lento&quot;

  • alert: QueueBuildup

expr: processing_queue_size &gt; 100

for: 5m

labels:

severity: warning

annotations:

summary: &quot;Fila de processamento acumulando&quot;</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>&lt;!-- FIM --&gt;</p>

Comentários

Mais em DevOps & CI/CD

Container Registry: Docker Hub, GHCR e Registry Privado com Harbor: Do Básico ao Avançado
Container Registry: Docker Hub, GHCR e Registry Privado com Harbor: Do Básico ao Avançado

O que é um Container Registry Um Container Registry é um repositório centrali...

Boas Práticas de Terraform Fundamentos: Providers, Resources, State e Plan para Times Ágeis
Boas Práticas de Terraform Fundamentos: Providers, Resources, State e Plan para Times Ágeis

Introdução ao Terraform Terraform é uma ferramenta de Infrastructure as Code...

Gerenciamento de Usuários, Grupos e Sudo em Ambientes de Produção: Do Básico ao Avançado
Gerenciamento de Usuários, Grupos e Sudo em Ambientes de Produção: Do Básico ao Avançado

Fundamentos de Gerenciamento de Usuários em Ambientes Linux Em ambientes de p...