---
name: format_prom_exposition
kind: function
lang: go
domain: infra
version: "1.0.0"
purity: pure
signature: "func FormatPromExposition(samples []PromSample, timestampMs int64) string"
description: "Convierte un slice de PromSample en texto con formato Prometheus exposition (una linea por sample: name{k=\"v\"} value timestampMs). Ordena labels por clave (salida determinista), escapa backslash/comilla/newline en valores de label, sanitiza el nombre de metrica a [a-zA-Z0-9_:], formatea el valor con FormatFloat 'g'. Si timestampMs<=0 omite el timestamp; sin labels omite las llaves. Funcion pura."
tags: [prometheus, exposition, metrics, format, fleet-metrics, infra, monitoring]
uses_functions: []
uses_types: ["PromSample_go_infra"]
returns: []
returns_optional: false
error_type: ""
imports: ["sort", "strconv", "strings"]
params:
  - name: samples
    desc: "slice de PromSample a serializar; cada uno aporta una linea de exposition"
  - name: timestampMs
    desc: "timestamp en milisegundos epoch a adjuntar a cada linea; si es <=0 se omite el campo timestamp"
output: "string con el texto exposition Prometheus, una linea por sample terminada en \\n. String vacio si samples esta vacio."
tested: true
tests:
  - "TestFormatPromExposition"
test_file_path: "functions/infra/format_prom_exposition_test.go"
file_path: "functions/infra/format_prom_exposition.go"
---

## Ejemplo

```go
samples := []PromSample{
    {Name: "node_load1", Value: 0.42},
    {Name: "node_cpu_core_percent", Labels: map[string]string{"core": "0"}, Value: 12.5},
    {Name: "node_disk_used_bytes", Labels: map[string]string{"mount": "/"}, Value: 1024},
}
text := FormatPromExposition(samples, 1700000000000)
// node_load1 0.42 1700000000000
// node_cpu_core_percent{core="0"} 12.5 1700000000000
// node_disk_used_bytes{mount="/"} 1024 1700000000000
```

## Cuando usarla

Cuando tengas un slice de PromSample (tipicamente de collect_host_metrics) y
necesites serializarlo al formato de texto que entienden los endpoints de
ingestion Prometheus (`/api/v1/import/prometheus` de VictoriaMetrics, pushgateway,
etc.). Es el paso intermedio del capability group `fleet-metrics`: colecta ->
formatea -> empuja. Al ser pura y determinista, tambien sirve para snapshots
reproducibles y golden tests.

## Gotchas

- El timestamp es **milisegundos** epoch (Prometheus exposition usa ms), no
  segundos. Pasa `time.Now().UnixMilli()`.
- `timestampMs <= 0` (incluido 0) omite el campo timestamp por completo.
- La label `instance` NO se gestiona aqui: si esta en `Labels` se serializa tal
  cual, pero la convencion del grupo es dejarla fuera y añadirla en el push via
  extra_label.
- No agrupa por nombre ni emite lineas `# HELP` / `# TYPE`: salida cruda de
  series, suficiente para ingestion pero no para un endpoint /metrics canonico.
- El nombre de metrica se sanitiza de forma destructiva: `node.cpu-percent!` se
  convierte en `node_cpu_percent_`. Nombra bien los samples en origen.
