Files
fn_registry/functions/infra/format_prom_exposition.go
T

87 lines
2.2 KiB
Go

package infra
import (
"sort"
"strconv"
"strings"
)
// FormatPromExposition convierte un slice de PromSample en texto con formato
// Prometheus exposition. Genera una linea por sample:
//
// name{k1="v1",k2="v2"} value timestampMs
//
// Reglas:
// - Si timestampMs <= 0, omite el campo timestamp.
// - Sin labels: "name value" (sin llaves).
// - Las labels se ordenan por clave (salida determinista).
// - En los valores de label se escapa: backslash -> \\, comilla -> \", newline -> \n.
// - El nombre de metrica se sanitiza a [a-zA-Z0-9_:] (el resto -> _).
// - El valor se formatea con strconv.FormatFloat(v, 'g', -1, 64).
//
// Es una funcion pura: no tiene efectos secundarios y la salida es deterministica
// para una entrada dada.
func FormatPromExposition(samples []PromSample, timestampMs int64) string {
var b strings.Builder
for _, s := range samples {
b.WriteString(sanitizeMetricName(s.Name))
if len(s.Labels) > 0 {
keys := make([]string, 0, len(s.Labels))
for k := range s.Labels {
keys = append(keys, k)
}
sort.Strings(keys)
b.WriteByte('{')
for i, k := range keys {
if i > 0 {
b.WriteByte(',')
}
b.WriteString(k)
b.WriteString(`="`)
b.WriteString(escapeLabelValue(s.Labels[k]))
b.WriteByte('"')
}
b.WriteByte('}')
}
b.WriteByte(' ')
b.WriteString(strconv.FormatFloat(s.Value, 'g', -1, 64))
if timestampMs > 0 {
b.WriteByte(' ')
b.WriteString(strconv.FormatInt(timestampMs, 10))
}
b.WriteByte('\n')
}
return b.String()
}
// sanitizeMetricName sustituye cualquier caracter fuera de [a-zA-Z0-9_:] por '_'.
func sanitizeMetricName(name string) string {
var b strings.Builder
b.Grow(len(name))
for _, r := range name {
if (r >= 'a' && r <= 'z') ||
(r >= 'A' && r <= 'Z') ||
(r >= '0' && r <= '9') ||
r == '_' || r == ':' {
b.WriteRune(r)
} else {
b.WriteByte('_')
}
}
return b.String()
}
// escapeLabelValue escapa los caracteres especiales del formato exposition en
// el valor de una label: backslash, comilla doble y newline.
func escapeLabelValue(v string) string {
v = strings.ReplaceAll(v, `\`, `\\`)
v = strings.ReplaceAll(v, `"`, `\"`)
v = strings.ReplaceAll(v, "\n", `\n`)
return v
}