package infra import ( "fmt" "io" "net/http" "net/url" "strings" "time" ) // PushPromRemote hace POST del body (texto en formato Prometheus exposition) al // endpoint dado, tipicamente el import de VictoriaMetrics // (".../api/v1/import/prometheus"). // // - Si user != "" usa Basic Auth con user/pass. // - extraLabels se adjuntan como query params repetidos // "extra_label=clave=valor" URL-encoded. VictoriaMetrics aƱade esas labels a // TODAS las series del push (util para la label "instance"). // - Content-Type: text/plain. // - http.Client con Timeout 10s y TLS verificado. // - Exito = status 2xx (VictoriaMetrics devuelve 204). Si no-2xx, retorna error // con el codigo y los primeros 200 bytes del cuerpo de respuesta. func PushPromRemote(endpoint string, user string, pass string, body string, extraLabels map[string]string) error { u, err := url.Parse(endpoint) if err != nil { return fmt.Errorf("parse endpoint %q: %w", endpoint, err) } if len(extraLabels) > 0 { q := u.Query() for k, v := range extraLabels { q.Add("extra_label", k+"="+v) } u.RawQuery = q.Encode() } req, err := http.NewRequest(http.MethodPost, u.String(), strings.NewReader(body)) if err != nil { return fmt.Errorf("build request: %w", err) } req.Header.Set("Content-Type", "text/plain") if user != "" { req.SetBasicAuth(user, pass) } client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { return fmt.Errorf("push to %q: %w", endpoint, err) } defer resp.Body.Close() if resp.StatusCode < 200 || resp.StatusCode >= 300 { snippet, _ := io.ReadAll(io.LimitReader(resp.Body, 200)) return fmt.Errorf("push to %q failed: status %d: %s", endpoint, resp.StatusCode, string(snippet)) } return nil }