A Veloz já coleta tráfego, CPU, memória e rede de todos os serviços. Métricas customizadas são as que só o seu código conhece: pedidos criados, mensagens na fila, tempo de processamento de um job.
Como funciona
Seu aplicativo expõe um endpoint HTTP no formato de exposição do Prometheus. A Veloz lê esse endpoint a cada 30 segundos e guarda as séries junto com as métricas de plataforma, dentro do espaço isolado da sua organização.
Você não configura endereço, credencial nem coletor. Basta declarar o endpoint no veloz.json.
O endpoint é lido pela rede interna da Veloz. Ele não fica acessível publicamente, mesmo quando a porta é diferente da porta do serviço.
Configuração
{
"services": {
"apps/api": {
"id": "svc_api456",
"name": "loja-api",
"type": "web",
"root": "apps/api",
"runtime": {
"command": "node dist/index.js",
"port": 3000
},
"observability": {
"metrics": { "port": 9090, "path": "/metrics" }
}
}
}
}| Campo | Padrão | Descrição |
|---|---|---|
enabled |
true |
false desliga a coleta sem apagar a configuração |
port |
O valor de runtime.port |
Porta onde o endpoint responde |
path |
/metrics |
Caminho do endpoint. Precisa começar com / |
Se o seu aplicativo serve as métricas na mesma porta HTTP do serviço, omita port:
{
"observability": {
"metrics": {}
}
}Depois de editar, rode veloz deploy. A primeira coleta acontece em até 30 segundos depois de o serviço ficar pronto.
Node e TypeScript
npm install prom-clientimport express from "express";
import { collectDefaultMetrics, register, Counter } from "prom-client";
collectDefaultMetrics();
export const pedidosCriados = new Counter({
name: "pedidos_criados_total",
help: "Total de pedidos criados",
});
const app = express();
app.get("/metrics", async (_req, res) => {
res.set("Content-Type", register.contentType);
res.end(await register.metrics());
});
app.listen(9090);collectDefaultMetrics() adiciona métricas de processo (uso de CPU, memória, event loop). Incremente o contador onde o evento acontece:
pedidosCriados.inc();Se você já tem um servidor Express na porta do serviço, registre a rota nele e omita metrics.port no veloz.json. Um segundo listen só é necessário quando você quer as métricas em uma porta separada.
Python
pip install prometheus-clientfrom prometheus_client import Counter, make_asgi_app
from fastapi import FastAPI
pedidos_criados = Counter("pedidos_criados_total", "Total de pedidos criados")
app = FastAPI()
app.mount("/metrics", make_asgi_app())Para aplicativos sem ASGI, sirva as métricas em uma porta própria:
from prometheus_client import start_http_server
start_http_server(9090)Incremente o contador com pedidos_criados.inc().
Go
go get github.com/prometheus/client_golang/prometheus/promhttppackage main
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var pedidosCriados = promauto.NewCounter(prometheus.CounterOpts{
Name: "pedidos_criados_total",
Help: "Total de pedidos criados",
})
func main() {
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":9090", nil)
}Incremente o contador com pedidosCriados.Inc().
Importante: o endpoint precisa escutar em todas as interfaces, não apenas em
127.0.0.1.http.ListenAndServe(":9090", nil)já faz isso. Em outras linguagens, confirme que o endereço de escuta é0.0.0.0e nãolocalhost.
Onde ver os dados
No painel, a aba Métricas do serviço traz a seção "Métricas do aplicativo", com um seletor das suas métricas e um gráfico. O seletor Taxa / Valor decide se a série é derivada no tempo: contadores (_total, _count) fazem mais sentido como taxa, gauges como valor.
Pelo terminal:
# Listar as métricas recebidas
veloz metrics list
# Consultar uma métrica sua
veloz metrics query 'rate(pedidos_criados_total[5m]) * 60' --start 1h
# Estado da coleta
veloz obs statusA sintaxe de consulta é MetricsQL, compatível com PromQL. Veja veloz metrics query-help para a referência completa.
Cardinalidade
Cardinalidade é a quantidade de séries distintas que uma métrica gera. Cada combinação de rótulos é uma série. É o único limite de métricas que costuma ser atingido por acidente, e a causa é sempre a mesma: um rótulo que carrega um valor único por requisição.
Nunca use como rótulo:
- Identificador de usuário, de sessão ou de requisição
- URL completa, incluindo query string
- Endereço de rede, timestamp ou mensagem de erro
Use o molde da rota, não a rota concreta:
// Errado: uma série nova por pedido, sem limite
requisicoes.inc({ rota: "/pedidos/8213" });
// Certo: uma série por molde de rota
requisicoes.inc({ rota: "/pedidos/:id" });Regra prática: um rótulo só entra se você consegue listar todos os valores possíveis. status (200, 404, 500) entra. user_id não.
Se você precisa do valor único para investigar um caso, ele pertence aos logs ou ao rastreamento, não a um rótulo de métrica.
Limites
| Limite | Valor | Observação |
|---|---|---|
| Séries ativas por serviço | 10.000 | O aviso de cardinalidade aparece a partir de 80% |
| Intervalo de coleta | 30 segundos | Fixo, não configurável |
| Tempo limite da coleta | 10 segundos | Acima disso o diagnóstico é "A coleta expirou" |
Respostas muito grandes também são recusadas pela coleta, e a causa é sempre cardinalidade. O painel avisa a partir de 80% do limite de séries, o que dá tempo de sobra para remover o rótulo culpado antes de chegar lá.
Próximos passos
- Observabilidade: visão geral e diagnósticos
- Rastreamento: instrumente com OpenTelemetry
- Painéis: painéis do Grafana versionados no repositório
- Métricas: métricas de plataforma e referência MetricsQL