Gráficos de métricas Grafana
Visão geral
Renderiza um gráfico de linha PNG no tema escuro do Grafana a partir de uma consulta PromQL, buscada através do proxy do datasource Grafana (sem necessidade de acesso direto à rede do Prometheus, apenas o token SA do Grafana é suficiente). Reprodutível e scriptável, ao contrário de uma captura de tela manual. Pode anexar o resultado diretamente a um problema do Jira.
Faça um snapshot primeiro quando um painel já mostrar os dados. Stacks do Grafana Cloud possuem renderização no servidor, então gcx dashboards snapshot retorna o painel real como PNG lá. Esta skill é para o que um snapshot não pode fornecer: uma comparação lado a lado entre consultas ou intervalos de tempo que nenhum painel individual codifica, e instâncias auto-hospedadas sem o plugin Image Renderer, onde o snapshot falha.
Pré-voo
Toda chamada Grafana aqui passa pelo gcx. Verifique uma vez por sessão:
command -v gcx >/dev/null || { echo "instale: brew install gcx"; exit 1; }
gcx config check || { echo "não pronto: gcx login"; exit 1; }
Acerta a consulta antes de desenhá-la. Esta skill renderiza qualquer PromQL que você passar, e uma consulta errada é pior aqui do que em um painel: o PNG cai em um ticket como evidência congelada que ninguém reexecuta, e parece oficial. HISTÓRICO NECESSÁRIO para a consulta em si: use a skill grafana-dashboards, seções PromQL essentials, Aggregation traps e Reading distributions and tails. Os que pegam em um gráfico de comparação: agregue depois de rate e nunca antes, envolva ambos os lados em max by (...) quando um rollout deixar duas séries por pod, nunca histogram_quantile um histograma exponencial base 2, e dê a cada subconsulta um passo explícito.
Quando usar
- Comparando 2+ séries: versão A vs B, canary vs controle, antes/depois de uma alteração.
- Anexando evidências a um ticket Jira, MR ou relatório de incidente.
- Renderização de painel Grafana falha (
gcx dashboards snapshoterro: sem Image Renderer nesse contexto auto-hospedado).
Não para: exploração interativa (use o Grafana), dados de valor único/tabela, ou captura de tela de um painel existente no Grafana Cloud (gcx dashboards snapshot).
Configuração (única)
matplotlib é necessário. Se estiver faltando, use um venv isolado (não polua o Python do sistema):
python3 -m venv ${CLAUDE_SKILL_DIR}/.venv
${CLAUDE_SKILL_DIR}/.venv/bin/pip install -q matplotlib
Referência rápida
| Necessidade | Flag |
|---|---|
| Qual datasource | --datasource-uid (encontre via gcx datasources list ou consultas de painel) |
| A consulta | --expr 'PromQL' |
| Janela de tempo | --start now-6h --end now --step 60 |
| Fonte do rótulo da série | --legend-key instance (padrão; qualquer rótulo de métrica) |
| Nomes mais bonitos | --rename '{"raw-value":"Nome Bonito"}' |
| Média/mín/máx por série | impressos no stdout após salvar (sem consulta extra) |
| Chamada no pico | --annotate-max "texto" |
| Qual Grafana | --grafana-url https://<host>: usa o contexto gcx cujo servidor tem aquele host (padrão: contexto atual do gcx) |
| Qual contexto gcx | --gcx-context <nome> (padrão $GCX_CONTEXT); para uma instância nomeada sem URL, escolha em gcx config list-contexts |
| Anexar ao Jira | --attach-jira ABC-123 (veja as variáveis de ambiente abaixo e o portão de aprovação no Fluxo de Trabalho) |
Ambiente
Nada é hardcoded: sem host, sem endereço. Defina estas no seu perfil do shell.
| Variável | Necessário para | Notas |
|---|---|---|
GRAFANA_URL + GRAFANA_TOKEN | token estático | o token é enviado apenas ao host de GRAFANA_URL (então GRAFANA_SERVICE_ACCOUNT_TOKEN, GTOK) |
GCX_CONTEXT | gcx | contexto gcx a forçar, igual a --gcx-context |
JIRA_API_TOKEN JIRA_EMAIL JIRA_BASE | --attach-jira apenas | todos os três, sem padrão |
Ordem de resolução, idêntica em toda skill Grafana: --token; --gcx-context / $GCX_CONTEXT; --grafana-url (o token de ambiente para o host de $GRAFANA_URL, senão o contexto gcx servindo aquele host, senão saia com o gcx login a executar); contexto atual do gcx; o token de ambiente quando gcx está faltando. Através do gcx, sua própria renovação OAuth se aplica e este script nunca lê ou armazena em cache uma credencial por si só. O resolvedor é duplicado em cada skill de propósito, para que qualquer uma funcione instalada sozinha.
Fluxo de trabalho
- Obtenha o UID do datasource + PromQL do painel (
gcx api /api/dashboards/uid/<uid>, leiapanels[*].targets[*].expr) ou escreva a consulta você mesmo. - Execute o script (via python do venv). As cores são atribuídas automaticamente da paleta Grafana na ordem das séries; a legenda mostra média/máx por série.
- Leia o PNG de volta para conferir antes de compartilhar.
- Opcionalmente, anexe ao Jira com
--attach-jira. É uma escrita no rastreador visível para toda a equipe: siga primeiro o portão de aprovação da skillticket-conventions(mostre o id do ticket e o PNG, aguarde um sim explícito). Um upload falho sai com código de erro não zero.
Exemplo (o canônico: memória de node HAProxy 3.2 vs 2.7)
VENV=${CLAUDE_SKILL_DIR}/.venv/bin/python
SKILL=${CLAUDE_SKILL_DIR}
export JIRA_API_TOKEN=$(zsh -l -c 'echo $JIRA_API_TOKEN') # apenas se anexar
export [email protected] JIRA_BASE=https://seudominio.atlassian.net
DS_UID=abc123XYZ # de `gcx datasources list`
$VENV $SKILL/plot_grafana.py \
--datasource-uid $DS_UID \
--expr '(1 - (node_memory_MemAvailable_bytes{instance=~"lb-edge-dc1-(1|4)"} / node_memory_MemTotal_bytes{instance=~"lb-edge-dc1-(1|4)"})) * 100' \
--start now-6h --step 60 \
--title "lb-edge - % de memória usada do node · 3.2 vs 2.7 (dc1, últimas 6h)" \
--ylabel "% Memória usada" --ymin 0 --ymax 45 \
--rename '{"lb-edge-dc1-1":"HAProxy 3.2.20 (dc1-1)","lb-edge-dc1-4":"HAProxy 2.7.11 (dc1-4, controle)"}' \
--annotate-max "recarga: worker antigo+novo coexistem → memória do node ~2x" \
--grafana-url https://grafana.exemplo.com \
--out ./mem-3.2-vs-2.7.png \
--attach-jira ABC-123
Erros comuns
- Gráfico desenhado a partir de uma consulta que ninguém verificou → veja a dica de PromQL acima; um número errado plausível é o modo de falha, não um erro.
- 401 do proxy → com um token estático, ele não pertence àquele host; através do gcx, o token de atualização expirou (aproximadamente mensal), execute
gcx login <context>. - Usando
python3do sistema →ModuleNotFoundError: matplotlib. Use o python do venv. - Linha vazia/plana onde você espera várias → a regex do
--exprcorrespondeu a uma única série; amplie o seletor de rótulo. - Séries sem nome / todas "series" →
--legend-keyaponta para um rótulo que a métrica não possui; escolha um que ela tenha (verifique o resultado bruto da consulta). :9100(ou qualquer:porta) nos nomes da legenda → removido automaticamente do nome derivado da série, então--renamevisa o host limpo (ex.:lb-edge-dc1-1, nãolb-edge-dc1-1:9100). Não precisa listar ambas as formas.- Tempos relativos aceitam um número e uma unidade, s/m/h/d (
now-90m,now-6h,now-2d). Compostos (now-1h30m), semanas (now-1w) e arredondamento (now/d) não são suportados: converta-os (now-90m,now-7d).