2022-12-10 10:09:21 +00:00
|
|
|
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")
|
2022-12-10 20:44:09 +00:00
|
|
|
|
2022-12-10 10:09:21 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-12-10 20:44:09 +00:00
|
|
|
dss := newDebugRelabelSteps(pcs, labels, false)
|
2022-12-10 10:09:21 +00:00
|
|
|
WriteMetricRelabelDebugSteps(w, dss, metric, relabelConfigs, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// WriteTargetRelabelDebug generates response for /target-relabel-debug page
|
2022-12-10 20:44:09 +00:00
|
|
|
func WriteTargetRelabelDebug(w http.ResponseWriter, r *http.Request) {
|
2022-12-10 10:09:21 +00:00
|
|
|
targetID := r.FormValue("id")
|
2022-12-10 20:44:09 +00:00
|
|
|
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
|
2022-12-10 10:09:21 +00:00
|
|
|
}
|
|
|
|
|
2022-12-10 20:44:09 +00:00
|
|
|
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
|
2022-12-10 10:09:21 +00:00
|
|
|
|
|
|
|
// Prevent from modifying the original labels
|
|
|
|
labels = labels.Clone()
|
|
|
|
|
|
|
|
// Apply relabeling
|
2022-12-10 20:44:09 +00:00
|
|
|
labelsResult, dss := pcs.ApplyDebug(labels.GetLabels())
|
2022-12-10 10:09:21 +00:00
|
|
|
labels.Labels = labelsResult
|
2022-12-10 20:44:09 +00:00
|
|
|
outStr := promrelabel.LabelsToString(labels.GetLabels())
|
2022-12-10 10:09:21 +00:00
|
|
|
|
2022-12-17 00:43:34 +00:00
|
|
|
if isTargetRelabel {
|
|
|
|
// Add missing instance label
|
|
|
|
if 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 {
|
2022-12-10 10:09:21 +00:00
|
|
|
dss = append(dss, promrelabel.DebugStep{
|
2022-12-17 00:43:34 +00:00
|
|
|
Rule: "remove labels with __ prefix",
|
|
|
|
In: inStr,
|
|
|
|
Out: outStr,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Remove labels with __ prefix except of __name__
|
|
|
|
inStr := outStr
|
|
|
|
labels.Labels = promrelabel.FinalizeLabels(labels.Labels[:0], labels.Labels)
|
|
|
|
outStr = promrelabel.LabelsToString(labels.GetLabels())
|
|
|
|
if inStr != outStr {
|
|
|
|
dss = append(dss, promrelabel.DebugStep{
|
|
|
|
Rule: "remove labels with __ prefix except of __name__",
|
2022-12-10 10:09:21 +00:00
|
|
|
In: inStr,
|
|
|
|
Out: outStr,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// There is no need in labels' sorting, since promrelabel.LabelsToString() automatically sorts labels.
|
2022-12-10 20:44:09 +00:00
|
|
|
return dss
|
2022-12-10 10:09:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|