feat(infra): grupo fleet-metrics — collect_host_metrics, format_prom_exposition, push_prom_remote, push_loki_stream, collect_battery_metrics + tipo PromSample (gopsutil; Android-safe: sin exec/pidfd, procesos via /proc)
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
---
|
||||
name: collect_battery_metrics
|
||||
kind: function
|
||||
lang: go
|
||||
domain: infra
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "func CollectBatteryMetrics() ([]PromSample, error)"
|
||||
description: "Recolecta metricas de bateria de un dispositivo Android via el comando termux-battery-status (paquete termux-api) y las devuelve como slice de PromSample con nombres estilo node_exporter: porcentaje, temperatura, estado de carga (booleano), corriente en microamperios y una serie informativa node_battery_health_info con labels health/status/plugged. Best-effort y multiplataforma: en nodos sin termux-battery-status (Linux normales) es un no-op que devuelve slice vacio y error nil; solo emite samples cuando el comando existe y responde JSON valido. El comando corre con timeout de 5s via context."
|
||||
tags: [prometheus, metrics, node-exporter, battery, termux, android, fleet-metrics, infra, monitoring]
|
||||
uses_functions: []
|
||||
uses_types: ["PromSample_go_infra"]
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: ["context", "encoding/json", "os/exec", "time"]
|
||||
params: []
|
||||
output: "slice de PromSample con metricas de bateria. node_battery_percent (0-100), node_battery_temp_celsius, node_battery_charging (1 si carga/lleno/enchufado, si no 0), node_battery_current_ua (microamperios, negativo al descargar) y node_battery_health_info{health,status,plugged} con value 1. En nodos sin termux-api devuelve slice vacio. Error nil siempre en condiciones normales: la funcion traga los fallos de ejecucion/parseo como no-op (slice vacio)."
|
||||
tested: true
|
||||
tests:
|
||||
- "TestCollectBatteryMetrics_ParseDischarging"
|
||||
- "TestCollectBatteryMetrics_ParseCharging"
|
||||
- "TestCollectBatteryMetrics_ParsePluggedNotUnplugged"
|
||||
- "TestCollectBatteryMetrics_ParseFull"
|
||||
- "TestCollectBatteryMetrics_InvalidJSON"
|
||||
test_file_path: "functions/infra/collect_battery_metrics_test.go"
|
||||
file_path: "functions/infra/collect_battery_metrics.go"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```go
|
||||
samples, err := CollectBatteryMetrics()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// En un Linux normal samples sera vacio (no-op); en Android/Termux trae
|
||||
// node_battery_percent, node_battery_temp_celsius, node_battery_charging, etc.
|
||||
// Componer con el resto del capability group fleet-metrics:
|
||||
host, _ := CollectHostMetrics()
|
||||
all := append(host, samples...)
|
||||
body := FormatPromExposition(all, time.Now().UnixMilli())
|
||||
err = PushPromRemote(
|
||||
"https://metrics-xxxx.organic-machine.com/api/v1/import/prometheus",
|
||||
"user", "pass",
|
||||
body,
|
||||
map[string]string{"instance": "pixel-phone"},
|
||||
)
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando un nodo de la flota es un movil Android con Termux + termux-api y quieres
|
||||
exponer la salud de su bateria como metricas Prometheus para push a un backend
|
||||
remoto (VictoriaMetrics, Mimir). Llamala junto a `collect_host_metrics_go_infra`
|
||||
en el loop del agente de monitorizacion push y concatena los slices: en moviles
|
||||
añade las series de bateria, en el resto de nodos no aporta nada (no-op seguro),
|
||||
asi puedes usar el MISMO agente en toda la flota sin ramas por plataforma.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Solo produce datos en Termux/Android con termux-api instalado**: necesita el
|
||||
binario `termux-battery-status` (paquete `termux-api` + la app Termux:API). En
|
||||
cualquier otro nodo (Linux de escritorio, VPS, macOS) `exec.LookPath` falla y
|
||||
la funcion es un no-op que devuelve `[]PromSample{}, nil`. No es un error:
|
||||
simplemente no hay bateria que reportar.
|
||||
- **No devuelve error nunca en condiciones normales**: por diseño best-effort,
|
||||
tanto el binario ausente como un comando fallido (timeout, permisos) o un JSON
|
||||
invalido se tragan como slice vacio. La firma mantiene `error` por convencion
|
||||
de impureza, pero el caller no necesita ramificar por error de plataforma.
|
||||
- **Timeout de 5s**: usa `exec.CommandContext` con `context.WithTimeout`. Si
|
||||
termux-api se cuelga, la llamada aborta a los 5s y devuelve no-op.
|
||||
- **node_battery_current_ua puede ser negativo**: convencion de Android — corriente
|
||||
negativa = descarga, positiva = carga. Se reporta tal cual (microamperios).
|
||||
- **node_battery_charging es heuristico**: vale 1 si `status` es `CHARGING` o
|
||||
`FULL`, o si `plugged != "UNPLUGGED"`. Cubre el caso de estar enchufado sin
|
||||
cargar activamente (ej. `NOT_CHARGING` con cargador conectado).
|
||||
- **No incluye la label `instance`**: igual que el resto de colectores del grupo,
|
||||
esa la añade `push_prom_remote_go_infra` via extra_label en el push.
|
||||
- **El parseo esta factorizado** en `parseBatteryJSON` (funcion pura interna) para
|
||||
poder testear los samples sin ejecutar termux-battery-status real.
|
||||
Reference in New Issue
Block a user