mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-22 16:36:27 +01:00
7e5555f9c7
Fixed decoding of label values with slash for pushgateway and prometheus golang client compatibility + added some tests. (#4962)
84 lines
2.1 KiB
Go
84 lines
2.1 KiB
Go
package common
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
|
|
)
|
|
|
|
// GetExtraLabels extracts name:value labels from `extra_label=name=value` query args from req.
|
|
//
|
|
// It also extracts Pushgateways-compatible extra labels from req.URL.Path
|
|
// according to https://github.com/prometheus/pushgateway#url .
|
|
func GetExtraLabels(req *http.Request) ([]prompbmarshal.Label, error) {
|
|
labels, err := getPushgatewayLabels(req.URL.Path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot parse pushgateway-style labels from %q: %w", req.URL.Path, err)
|
|
}
|
|
q := req.URL.Query()
|
|
for _, label := range q["extra_label"] {
|
|
tmp := strings.SplitN(label, "=", 2)
|
|
if len(tmp) != 2 {
|
|
return nil, fmt.Errorf("`extra_label` query arg must have the format `name=value`; got %q", label)
|
|
}
|
|
labels = append(labels, prompbmarshal.Label{
|
|
Name: tmp[0],
|
|
Value: tmp[1],
|
|
})
|
|
}
|
|
return labels, nil
|
|
}
|
|
|
|
func getPushgatewayLabels(path string) ([]prompbmarshal.Label, error) {
|
|
n := strings.Index(path, "/metrics/job")
|
|
if n < 0 {
|
|
return nil, nil
|
|
}
|
|
s := path[n+len("/metrics/"):]
|
|
if !strings.HasPrefix(s, "job/") && !strings.HasPrefix(s, "job@base64/") {
|
|
return nil, nil
|
|
}
|
|
labelsCount := (strings.Count(s, "/") + 1) / 2
|
|
labels := make([]prompbmarshal.Label, 0, labelsCount)
|
|
for len(s) > 0 {
|
|
n := strings.IndexByte(s, '/')
|
|
if n < 0 {
|
|
return nil, fmt.Errorf("missing value for label %q", s)
|
|
}
|
|
name := s[:n]
|
|
s = s[n+1:]
|
|
isBase64 := strings.HasSuffix(name, "@base64")
|
|
if isBase64 {
|
|
name = name[:len(name)-len("@base64")]
|
|
}
|
|
var value string
|
|
n = strings.IndexByte(s, '/')
|
|
if n < 0 {
|
|
value = s
|
|
s = ""
|
|
} else {
|
|
value = s[:n]
|
|
s = s[n+1:]
|
|
}
|
|
if isBase64 {
|
|
data, err := base64.RawURLEncoding.DecodeString(strings.TrimRight(value, "="))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot base64-decode value=%q for label=%q: %w", value, name, err)
|
|
}
|
|
value = string(data)
|
|
}
|
|
if len(value) == 0 {
|
|
// Skip labels with empty values
|
|
continue
|
|
}
|
|
labels = append(labels, prompbmarshal.Label{
|
|
Name: name,
|
|
Value: value,
|
|
})
|
|
}
|
|
return labels, nil
|
|
}
|