mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-04-20 16:09:25 +00:00
lib/promscrape: support filtering targets via scrapePool
GET param in /api/v1/targets
API (#8611)
This improves compatibility with Prometheus `/api/v1/targets` API.
https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5343
---------
Signed-off-by: hagen1778 <roman@victoriametrics.com>
Co-authored-by: Zakhar Bessarab <z.bessarab@victoriametrics.com>
(cherry picked from commit a2ba37be68
)
Signed-off-by: hagen1778 <roman@victoriametrics.com>
This commit is contained in:
parent
fc341ac05b
commit
df98840167
4 changed files with 78 additions and 9 deletions
app/vmagent
docs/victoriametrics/changelog
lib/promscrape
|
@ -443,8 +443,10 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool {
|
|||
case "/prometheus/api/v1/targets", "/api/v1/targets":
|
||||
promscrapeAPIV1TargetsRequests.Inc()
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
// https://prometheus.io/docs/prometheus/latest/querying/api/#targets
|
||||
state := r.FormValue("state")
|
||||
promscrape.WriteAPIV1Targets(w, state)
|
||||
scrapePool := r.FormValue("scrapePool")
|
||||
promscrape.WriteAPIV1Targets(w, state, scrapePool)
|
||||
return true
|
||||
case "/prometheus/target_response", "/target_response":
|
||||
promscrapeTargetResponseRequests.Inc()
|
||||
|
|
|
@ -19,6 +19,7 @@ See also [LTS releases](https://docs.victoriametrics.com/lts-releases/).
|
|||
## tip
|
||||
|
||||
* FEATURE: [dashboards/single](https://grafana.com/grafana/dashboards/10229), [dashboards/cluster](https://grafana.com/grafana/dashboards/11176): remove panel `Storage full ETA` as it could have showing incorrect predictions and result in user's confusion. See more details in [this PR](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/8492).
|
||||
* FEATURE: [vmsingle](https://docs.victoriametrics.com/single-server-victoriametrics/), [vmagent](https://docs.victoriametrics.com/vmagent/): support filtering targets via `scrapePool` GET param in `/api/v1/targets` API.
|
||||
|
||||
* BUGFIX: [vmgateway](https://docs.victoriametrics.com/vmgateway): properly set the `Host` header when routing requests to `-write.url` and `-read.url`, which is needed for reverse proxies like Traefik.
|
||||
* BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert/) for [VictoriaMetrics enterprise](https://docs.victoriametrics.com/enterprise.html): properly attach tenant labels `vm_account_id` and `vm_project_id` to alerting rules when enabling `-clusterMode`. Previously, these labels were lost in alert messages to Alertmanager. Bug was introduced in [v1.112.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.112.0).
|
||||
|
|
|
@ -68,13 +68,13 @@ func WriteServiceDiscovery(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
// WriteAPIV1Targets writes /api/v1/targets to w according to https://prometheus.io/docs/prometheus/latest/querying/api/#targets
|
||||
func WriteAPIV1Targets(w io.Writer, state string) {
|
||||
func WriteAPIV1Targets(w io.Writer, state, scrapePool string) {
|
||||
if state == "" {
|
||||
state = "any"
|
||||
}
|
||||
fmt.Fprintf(w, `{"status":"success","data":{"activeTargets":`)
|
||||
if state == "active" || state == "any" {
|
||||
tsmGlobal.WriteActiveTargetsJSON(w)
|
||||
tsmGlobal.WriteActiveTargetsJSON(w, scrapePool)
|
||||
} else {
|
||||
fmt.Fprintf(w, `[]`)
|
||||
}
|
||||
|
@ -254,16 +254,24 @@ func (tsm *targetStatusMap) getActiveTargetStatuses() []targetStatus {
|
|||
}
|
||||
|
||||
// WriteActiveTargetsJSON writes `activeTargets` contents to w according to https://prometheus.io/docs/prometheus/latest/querying/api/#targets
|
||||
func (tsm *targetStatusMap) WriteActiveTargetsJSON(w io.Writer) {
|
||||
func (tsm *targetStatusMap) WriteActiveTargetsJSON(w io.Writer, scrapePoolFilter string) {
|
||||
tss := tsm.getActiveTargetStatuses()
|
||||
fmt.Fprintf(w, `[`)
|
||||
for i, ts := range tss {
|
||||
var needComma bool
|
||||
for _, ts := range tss {
|
||||
scrapePool := ts.sw.Config.jobNameOriginal
|
||||
if scrapePoolFilter != "" && scrapePool != scrapePoolFilter {
|
||||
continue
|
||||
}
|
||||
if needComma {
|
||||
fmt.Fprintf(w, `,`)
|
||||
}
|
||||
fmt.Fprintf(w, `{"discoveredLabels":`)
|
||||
writeLabelsJSON(w, ts.sw.Config.OriginalLabels)
|
||||
fmt.Fprintf(w, `,"labels":`)
|
||||
writeLabelsJSON(w, ts.sw.Config.Labels)
|
||||
// see https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5343
|
||||
fmt.Fprintf(w, `,"scrapePool":%s`, stringsutil.JSONString(ts.sw.Config.jobNameOriginal))
|
||||
fmt.Fprintf(w, `,"scrapePool":%s`, stringsutil.JSONString(scrapePool))
|
||||
fmt.Fprintf(w, `,"scrapeUrl":%s`, stringsutil.JSONString(ts.sw.Config.ScrapeURL))
|
||||
errMsg := ""
|
||||
if ts.err != nil {
|
||||
|
@ -278,9 +286,7 @@ func (tsm *targetStatusMap) WriteActiveTargetsJSON(w io.Writer) {
|
|||
state = "down"
|
||||
}
|
||||
fmt.Fprintf(w, `,"health":%s}`, stringsutil.JSONString(state))
|
||||
if i+1 < len(tss) {
|
||||
fmt.Fprintf(w, `,`)
|
||||
}
|
||||
needComma = true
|
||||
}
|
||||
fmt.Fprintf(w, `]`)
|
||||
}
|
||||
|
|
60
lib/promscrape/targetstatus_test.go
Normal file
60
lib/promscrape/targetstatus_test.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
package promscrape
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutil"
|
||||
)
|
||||
|
||||
func TestWriteActiveTargetsJSON(t *testing.T) {
|
||||
tsm := newTargetStatusMap()
|
||||
tsm.Register(&scrapeWork{
|
||||
Config: &ScrapeWork{
|
||||
jobNameOriginal: "foo",
|
||||
OriginalLabels: promutil.NewLabelsFromMap(map[string]string{
|
||||
"__address__": "host1:80",
|
||||
}),
|
||||
},
|
||||
})
|
||||
tsm.Register(&scrapeWork{
|
||||
Config: &ScrapeWork{
|
||||
jobNameOriginal: "bar",
|
||||
OriginalLabels: promutil.NewLabelsFromMap(map[string]string{
|
||||
"__address__": "host2:80",
|
||||
}),
|
||||
},
|
||||
})
|
||||
|
||||
type activeTarget struct {
|
||||
DiscoveredLabels map[string]string `json:"discoveredLabels"`
|
||||
ScrapePool string `json:"scrapePool"`
|
||||
}
|
||||
f := func(scrapePoolFilter string, exp []activeTarget) {
|
||||
t.Helper()
|
||||
b := &bytes.Buffer{}
|
||||
tsm.WriteActiveTargetsJSON(b, scrapePoolFilter)
|
||||
|
||||
var got []activeTarget
|
||||
if err := json.Unmarshal(b.Bytes(), &got); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(got, exp) {
|
||||
t.Fatalf("unexpected response; \ngot\n %s; \nwant\n %s", got, exp)
|
||||
}
|
||||
}
|
||||
|
||||
f("", []activeTarget{
|
||||
{ScrapePool: "foo", DiscoveredLabels: map[string]string{"__address__": "host1:80"}},
|
||||
{ScrapePool: "bar", DiscoveredLabels: map[string]string{"__address__": "host2:80"}},
|
||||
})
|
||||
f("foo", []activeTarget{
|
||||
{ScrapePool: "foo", DiscoveredLabels: map[string]string{"__address__": "host1:80"}},
|
||||
})
|
||||
f("bar", []activeTarget{
|
||||
{ScrapePool: "bar", DiscoveredLabels: map[string]string{"__address__": "host2:80"}},
|
||||
})
|
||||
f("unknown", []activeTarget{})
|
||||
}
|
Loading…
Reference in a new issue