Monitoramento APM customizado pra Protheus
Como instrumentar Protheus pra APM (DataDog, NewRelic, Grafana). Traces, metricas, dashboards. Identificar gargalos antes do usuario reclamar.
APM (Application Performance Monitoring) e o "raio-X" da aplicacao em producao. Protheus nao tem APM nativo, mas voce constroi um com FwLogger + tabela Z + integracao com Prometheus/DataDog.
O que monitorar
| Metrica | Por que |
|---|---|
| Tempo de resposta de rotina | Identificar lentidao |
| Throughput (op/min) | Capacidade do sistema |
| Taxa de erro | Saude funcional |
| Uso de licencas | Saturation |
| Sessoes ativas | Concorrencia |
| Locks no banco | Contensao |
| Tempo de query SQL | Gargalo de banco |
Instrumentar rotinas — wrapper de timing
function Instrumentar(cRotina, bAcao)
Local nIni := Seconds()
Local lOk := .T.
Local cErro := ""
try
Eval(bAcao)
catch e
lOk := .F.
cErro := e:getDescription()
endtry
Local nDur := (Seconds() - nIni) * 1000 // ms
// Loga
FwLogger():Info("rotina-executada", {;
"rotina": cRotina, ;
"ms": nDur, ;
"ok": lOk, ;
"user": RetCodUsr(),;
"filial": cFilAnt, ;
"erro": cErro ;
})
// Persiste em tabela Z pra agregacao
RecLock("ZMET", .T.)
ZMET->ZMET_DATA := dDataBase
ZMET->ZMET_HORA := Time()
ZMET->ZMET_ROTINA := cRotina
ZMET->ZMET_MS := nDur
ZMET->ZMET_OK := lOk
ZMET->(MsUnlock())
return lOk
Uso
// Em vez de chamar direto
U_GeraNF()
// Instrumente
Instrumentar("GeraNF", {|| U_GeraNF()})
Exportar pra Prometheus (pull-based)
@Get("/metrics")
function MetricasProm()
Local cOut := ""
// Counters acumulados
cOut += "# HELP protheus_rotinas_total Numero total de execucoes" + CRLF
cOut += "# TYPE protheus_rotinas_total counter" + CRLF
Local cQry := "SELECT ZMET_ROTINA, COUNT(*) AS N " + ;
" FROM " + RetSqlName("ZMET") + ;
" WHERE ZMET_DATA = '" + DToS(dDataBase) + "'" + ;
" GROUP BY ZMET_ROTINA"
TCQuery cQry New Alias "M"
While !M->(Eof())
cOut += 'protheus_rotinas_total{rotina="' + AllTrim(M->ZMET_ROTINA) + '"} ' + ;
cValToChar(M->N) + CRLF
M->(DBSkip())
EndDo
M->(DBCloseArea())
// Histograma de duracao
cOut += "# HELP protheus_rotina_duration_seconds Duracao de rotinas" + CRLF
cOut += "# TYPE protheus_rotina_duration_seconds histogram" + CRLF
// ... gerar buckets
oResponse:setContentType("text/plain")
oResponse:setBody(cOut)
return
Prometheus scrape config
# /etc/prometheus/prometheus.yml
scrape_configs:
- job_name: 'protheus'
scrape_interval: 30s
metrics_path: /metrics
static_configs:
- targets: ['protheus.empresa.com.br:8080']
Dashboard Grafana
Importe template "Protheus Custom" (criado por voce) com paineis:
- Top 10 rotinas mais lentas
- Taxa de erro por rotina
- Sessoes ativas no tempo
- Heatmap de horarios de pico
Alertas no AlertManager
groups:
- name: protheus
rules:
- alert: ProtheusLento
expr: avg(protheus_rotina_duration_seconds) > 5
for: 5m
annotations:
summary: Rotina demorando >5s em media
- alert: ProtheusTaxaErroAlta
expr: rate(protheus_erros_total[5m]) > 0.1
for: 2m
annotations:
summary: Mais de 10% de erro nos ultimos 5min
Integracoes prontas
| Tool | Pra que |
|---|---|
| Prometheus + Grafana | Open source, mais comum |
| DataDog | SaaS robusto, mais caro |
| NewRelic | SaaS, foco em traces |
| Elastic APM | Integracao natural com Kibana |
| Dynatrace | Enterprise, auto-discovery |
Pegadinhas
- Tabela ZMET cresce rapido — milhares de registros/dia. Particionar e limpar > 30 dias.
- Performance de instrumentacao: nao pode adicionar > 5% de overhead. Use FwLogger debug condicional.
- Metricas sensiveis: nao logue PII. Use codigos/IDs.
- Cardinalidade: cuidado com labels com muitos valores unicos (ex: ID do pedido) — explode metricas.