VictoriaMetrics/lib/promscrape/relabel_debug.go

141 lines
4.2 KiB
Go

package promscrape
import (
"fmt"
"net/http"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promrelabel"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
// WriteMetricRelabelDebug serves requests to /metric-relabel-debug page
func WriteMetricRelabelDebug(w http.ResponseWriter, r *http.Request) {
metric := r.FormValue("metric")
relabelConfigs := r.FormValue("relabel_configs")
if metric == "" {
metric = "{}"
}
labels, err := promutils.NewLabelsFromString(metric)
if err != nil {
err = fmt.Errorf("cannot parse metric: %s", err)
WriteMetricRelabelDebugSteps(w, nil, metric, relabelConfigs, err)
return
}
pcs, err := promrelabel.ParseRelabelConfigsData([]byte(relabelConfigs))
if err != nil {
err = fmt.Errorf("cannot parse relabel configs: %s", err)
WriteMetricRelabelDebugSteps(w, nil, metric, relabelConfigs, err)
return
}
dss := newDebugRelabelSteps(pcs, labels, false)
WriteMetricRelabelDebugSteps(w, dss, metric, relabelConfigs, nil)
}
// WriteTargetRelabelDebug generates response for /target-relabel-debug page
func WriteTargetRelabelDebug(w http.ResponseWriter, r *http.Request) {
targetID := r.FormValue("id")
metric := r.FormValue("metric")
relabelConfigs := r.FormValue("relabel_configs")
if metric == "" && relabelConfigs == "" {
if targetID == "" {
metric = "{}"
WriteTargetRelabelDebugSteps(w, targetID, nil, metric, relabelConfigs, nil)
return
}
pcs, labels, ok := getRelabelContextByTargetID(targetID)
if !ok {
err := fmt.Errorf("cannot find target for id=%s", targetID)
targetID = ""
WriteTargetRelabelDebugSteps(w, targetID, nil, metric, relabelConfigs, err)
return
}
metric = labels.String()
relabelConfigs = pcs.String()
dss := newDebugRelabelSteps(pcs, labels, true)
WriteTargetRelabelDebugSteps(w, targetID, dss, metric, relabelConfigs, nil)
return
}
if metric == "" {
metric = "{}"
}
labels, err := promutils.NewLabelsFromString(metric)
if err != nil {
err = fmt.Errorf("cannot parse metric: %s", err)
WriteTargetRelabelDebugSteps(w, targetID, nil, metric, relabelConfigs, err)
return
}
pcs, err := promrelabel.ParseRelabelConfigsData([]byte(relabelConfigs))
if err != nil {
err = fmt.Errorf("cannot parse relabel configs: %s", err)
WriteTargetRelabelDebugSteps(w, targetID, nil, metric, relabelConfigs, err)
return
}
dss := newDebugRelabelSteps(pcs, labels, true)
WriteTargetRelabelDebugSteps(w, targetID, dss, metric, relabelConfigs, nil)
}
func newDebugRelabelSteps(pcs *promrelabel.ParsedConfigs, labels *promutils.Labels, isTargetRelabel bool) []promrelabel.DebugStep {
// The target relabeling below must be in sync with the code at scrapeWorkConfig.getScrapeWork if isTragetRelabeling=true
// and with the code at scrapeWork.addRowToTimeseries when isTargetRelabeling=false
// Prevent from modifying the original labels
labels = labels.Clone()
// Apply relabeling
labelsResult, dss := pcs.ApplyDebug(labels.GetLabels())
labels.Labels = labelsResult
outStr := promrelabel.LabelsToString(labels.GetLabels())
// Add missing instance label
if isTargetRelabel && labels.Get("instance") == "" {
address := labels.Get("__address__")
if address != "" {
inStr := outStr
labels.Add("instance", address)
outStr = promrelabel.LabelsToString(labels.GetLabels())
dss = append(dss, promrelabel.DebugStep{
Rule: "add missing instance label from __address__ label",
In: inStr,
Out: outStr,
})
}
}
// Remove labels with __ prefix
inStr := outStr
labels.RemoveLabelsWithDoubleUnderscorePrefix()
outStr = promrelabel.LabelsToString(labels.GetLabels())
if inStr != outStr {
dss = append(dss, promrelabel.DebugStep{
Rule: "remove labels with __ prefix",
In: inStr,
Out: outStr,
})
}
// There is no need in labels' sorting, since promrelabel.LabelsToString() automatically sorts labels.
return dss
}
func getChangedLabelNames(in, out *promutils.Labels) map[string]struct{} {
inMap := in.ToMap()
outMap := out.ToMap()
changed := make(map[string]struct{})
for k, v := range outMap {
inV, ok := inMap[k]
if !ok || inV != v {
changed[k] = struct{}{}
}
}
for k, v := range inMap {
outV, ok := outMap[k]
if !ok || outV != v {
changed[k] = struct{}{}
}
}
return changed
}