mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-15 00:13:30 +01:00
lib/promscrape: add exported_
prefix to metric names exported by scrape targets if they clash with automatically generated metrics
Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3406
This commit is contained in:
parent
ab96fed372
commit
8ce5b095b7
@ -317,7 +317,8 @@ Extra labels can be added to metrics collected by `vmagent` via the following me
|
|||||||
|
|
||||||
## Automatically generated metrics
|
## Automatically generated metrics
|
||||||
|
|
||||||
`vmagent` automatically generates the following metrics per each scrape of every [Prometheus-compatible target](#how-to-collect-metrics-in-prometheus-format):
|
`vmagent` automatically generates the following metrics per each scrape of every [Prometheus-compatible target](#how-to-collect-metrics-in-prometheus-format)
|
||||||
|
and attaches target-specific `instance` and `job` labels to these metrics:
|
||||||
|
|
||||||
* `up` - this metric exposes `1` value on successful scrape and `0` value on unsuccessful scrape. This allows monitoring
|
* `up` - this metric exposes `1` value on successful scrape and `0` value on unsuccessful scrape. This allows monitoring
|
||||||
failing scrapes with the following [MetricsQL query](https://docs.victoriametrics.com/MetricsQL.html):
|
failing scrapes with the following [MetricsQL query](https://docs.victoriametrics.com/MetricsQL.html):
|
||||||
@ -405,6 +406,9 @@ Extra labels can be added to metrics collected by `vmagent` via the following me
|
|||||||
sum_over_time(scrape_series_limit_samples_dropped[1h]) > 0
|
sum_over_time(scrape_series_limit_samples_dropped[1h]) > 0
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If the target exports metrics with names clashing with the automatically generated metric names, then `vmagent` automatically
|
||||||
|
adds `exported_` prefix to these metric names, so they don't clash with automatically generated metric names.
|
||||||
|
|
||||||
|
|
||||||
## Relabeling
|
## Relabeling
|
||||||
|
|
||||||
|
@ -15,6 +15,8 @@ The following tip changes can be tested by building VictoriaMetrics components f
|
|||||||
|
|
||||||
## tip
|
## tip
|
||||||
|
|
||||||
|
* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): add `exported_` prefix to metric names exported by scrape targets if these metric names clash with [automatically generated metrics](https://docs.victoriametrics.com/vmagent.html#automatically-generated-metrics) such as `up`, `scrape_samples_scraped`, etc. This prevents from corruption of automatically generated metrics. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3406).
|
||||||
|
|
||||||
|
|
||||||
## [v1.84.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.84.0)
|
## [v1.84.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.84.0)
|
||||||
|
|
||||||
|
@ -321,7 +321,8 @@ Extra labels can be added to metrics collected by `vmagent` via the following me
|
|||||||
|
|
||||||
## Automatically generated metrics
|
## Automatically generated metrics
|
||||||
|
|
||||||
`vmagent` automatically generates the following metrics per each scrape of every [Prometheus-compatible target](#how-to-collect-metrics-in-prometheus-format):
|
`vmagent` automatically generates the following metrics per each scrape of every [Prometheus-compatible target](#how-to-collect-metrics-in-prometheus-format)
|
||||||
|
and attaches target-specific `instance` and `job` labels to these metrics:
|
||||||
|
|
||||||
* `up` - this metric exposes `1` value on successful scrape and `0` value on unsuccessful scrape. This allows monitoring
|
* `up` - this metric exposes `1` value on successful scrape and `0` value on unsuccessful scrape. This allows monitoring
|
||||||
failing scrapes with the following [MetricsQL query](https://docs.victoriametrics.com/MetricsQL.html):
|
failing scrapes with the following [MetricsQL query](https://docs.victoriametrics.com/MetricsQL.html):
|
||||||
@ -409,6 +410,9 @@ Extra labels can be added to metrics collected by `vmagent` via the following me
|
|||||||
sum_over_time(scrape_series_limit_samples_dropped[1h]) > 0
|
sum_over_time(scrape_series_limit_samples_dropped[1h]) > 0
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If the target exports metrics with names clashing with the automatically generated metric names, then `vmagent` automatically
|
||||||
|
adds `exported_` prefix to these metric names, so they don't clash with automatically generated metric names.
|
||||||
|
|
||||||
|
|
||||||
## Relabeling
|
## Relabeling
|
||||||
|
|
||||||
|
@ -811,6 +811,18 @@ type autoMetrics struct {
|
|||||||
seriesLimitSamplesDropped int
|
seriesLimitSamplesDropped int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isAutoMetric(s string) bool {
|
||||||
|
switch s {
|
||||||
|
case "up", "scrape_duration_seconds", "scrape_samples_scraped",
|
||||||
|
"scrape_samples_post_metric_relabeling", "scrape_series_added",
|
||||||
|
"scrape_timeout_seconds", "scrape_samples_limit",
|
||||||
|
"scrape_series_limit_samples_dropped", "scrape_series_limit",
|
||||||
|
"scrape_series_current":
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (sw *scrapeWork) addAutoMetrics(am *autoMetrics, wc *writeRequestCtx, timestamp int64) {
|
func (sw *scrapeWork) addAutoMetrics(am *autoMetrics, wc *writeRequestCtx, timestamp int64) {
|
||||||
sw.addAutoTimeseries(wc, "up", float64(am.up), timestamp)
|
sw.addAutoTimeseries(wc, "up", float64(am.up), timestamp)
|
||||||
sw.addAutoTimeseries(wc, "scrape_duration_seconds", am.scrapeDurationSeconds, timestamp)
|
sw.addAutoTimeseries(wc, "scrape_duration_seconds", am.scrapeDurationSeconds, timestamp)
|
||||||
@ -842,8 +854,16 @@ func (sw *scrapeWork) addAutoTimeseries(wc *writeRequestCtx, name string, value
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sw *scrapeWork) addRowToTimeseries(wc *writeRequestCtx, r *parser.Row, timestamp int64, needRelabel bool) {
|
func (sw *scrapeWork) addRowToTimeseries(wc *writeRequestCtx, r *parser.Row, timestamp int64, needRelabel bool) {
|
||||||
|
metric := r.Metric
|
||||||
|
if needRelabel && isAutoMetric(metric) {
|
||||||
|
bb := bbPool.Get()
|
||||||
|
bb.B = append(bb.B, "exported_"...)
|
||||||
|
bb.B = append(bb.B, metric...)
|
||||||
|
metric = bytesutil.InternString(bytesutil.ToUnsafeString(bb.B))
|
||||||
|
bbPool.Put(bb)
|
||||||
|
}
|
||||||
labelsLen := len(wc.labels)
|
labelsLen := len(wc.labels)
|
||||||
wc.labels = appendLabels(wc.labels, r.Metric, r.Tags, sw.Config.Labels, sw.Config.HonorLabels)
|
wc.labels = appendLabels(wc.labels, metric, r.Tags, sw.Config.Labels, sw.Config.HonorLabels)
|
||||||
if needRelabel {
|
if needRelabel {
|
||||||
wc.labels = sw.Config.MetricRelabelConfigs.Apply(wc.labels, labelsLen)
|
wc.labels = sw.Config.MetricRelabelConfigs.Apply(wc.labels, labelsLen)
|
||||||
}
|
}
|
||||||
@ -870,6 +890,8 @@ func (sw *scrapeWork) addRowToTimeseries(wc *writeRequestCtx, r *parser.Row, tim
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var bbPool bytesutil.ByteBufferPool
|
||||||
|
|
||||||
func appendLabels(dst []prompbmarshal.Label, metric string, src []parser.Tag, extraLabels []prompbmarshal.Label, honorLabels bool) []prompbmarshal.Label {
|
func appendLabels(dst []prompbmarshal.Label, metric string, src []parser.Tag, extraLabels []prompbmarshal.Label, honorLabels bool) []prompbmarshal.Label {
|
||||||
dstLen := len(dst)
|
dstLen := len(dst)
|
||||||
dst = append(dst, prompbmarshal.Label{
|
dst = append(dst, prompbmarshal.Label{
|
||||||
|
@ -12,6 +12,30 @@ import (
|
|||||||
parser "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/prometheus"
|
parser "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/prometheus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestIsAutoMetric(t *testing.T) {
|
||||||
|
f := func(metric string, resultExpected bool) {
|
||||||
|
t.Helper()
|
||||||
|
result := isAutoMetric(metric)
|
||||||
|
if result != resultExpected {
|
||||||
|
t.Fatalf("unexpected result for isAutoMetric(%q); got %v; want %v", metric, result, resultExpected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f("up", true)
|
||||||
|
f("scrape_duration_seconds", true)
|
||||||
|
f("scrape_samples_scraped", true)
|
||||||
|
f("scrape_samples_post_metric_relabeling", true)
|
||||||
|
f("scrape_series_added", true)
|
||||||
|
f("scrape_timeout_seconds", true)
|
||||||
|
f("scrape_samples_limit", true)
|
||||||
|
f("scrape_series_limit_samples_dropped", true)
|
||||||
|
f("scrape_series_limit", true)
|
||||||
|
f("scrape_series_current", true)
|
||||||
|
|
||||||
|
f("foobar", false)
|
||||||
|
f("exported_up", false)
|
||||||
|
f("upx", false)
|
||||||
|
}
|
||||||
|
|
||||||
func TestAppendExtraLabels(t *testing.T) {
|
func TestAppendExtraLabels(t *testing.T) {
|
||||||
f := func(sourceLabels, extraLabels string, honorLabels bool, resultExpected string) {
|
f := func(sourceLabels, extraLabels string, honorLabels bool, resultExpected string) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
@ -385,6 +409,25 @@ func TestScrapeWorkScrapeInternalSuccess(t *testing.T) {
|
|||||||
scrape_series_added{job="xx",instance="foo.com"} 4 123
|
scrape_series_added{job="xx",instance="foo.com"} 4 123
|
||||||
scrape_timeout_seconds{job="xx",instance="foo.com"} 42 123
|
scrape_timeout_seconds{job="xx",instance="foo.com"} 42 123
|
||||||
`)
|
`)
|
||||||
|
// Scrape metrics with names clashing with auto metrics
|
||||||
|
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3406
|
||||||
|
f(`
|
||||||
|
up{bar="baz"} 34.44
|
||||||
|
bar{a="b",c="d"} -3e4
|
||||||
|
scrape_series_added 3.435
|
||||||
|
`, &ScrapeWork{
|
||||||
|
ScrapeTimeout: time.Second * 42,
|
||||||
|
}, `
|
||||||
|
exported_up{bar="baz"} 34.44 123
|
||||||
|
exported_scrape_series_added 3.435 123
|
||||||
|
bar{a="b",c="d"} -3e4 123
|
||||||
|
up 1 123
|
||||||
|
scrape_samples_scraped 3 123
|
||||||
|
scrape_duration_seconds 0 123
|
||||||
|
scrape_samples_post_metric_relabeling 3 123
|
||||||
|
scrape_series_added 3 123
|
||||||
|
scrape_timeout_seconds 42 123
|
||||||
|
`)
|
||||||
// Scrape success with the given SampleLimit.
|
// Scrape success with the given SampleLimit.
|
||||||
f(`
|
f(`
|
||||||
foo{bar="baz"} 34.44
|
foo{bar="baz"} 34.44
|
||||||
|
@ -8,6 +8,48 @@ import (
|
|||||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompbmarshal"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func BenchmarkIsAutoMetricMiss(b *testing.B) {
|
||||||
|
metrics := []string{
|
||||||
|
"process_cpu_seconds_total",
|
||||||
|
"process_resident_memory_bytes",
|
||||||
|
"vm_tcplistener_read_calls_total",
|
||||||
|
"http_requests_total",
|
||||||
|
"node_cpu_seconds_total",
|
||||||
|
}
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.SetBytes(1)
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
for _, metric := range metrics {
|
||||||
|
if isAutoMetric(metric) {
|
||||||
|
panic(fmt.Errorf("BUG: %q mustn't be detected as auto metric", metric))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkIsAutoMetricHit(b *testing.B) {
|
||||||
|
metrics := []string{
|
||||||
|
"up",
|
||||||
|
"scrape_duration_seconds",
|
||||||
|
"scrape_series_current",
|
||||||
|
"scrape_samples_scraped",
|
||||||
|
"scrape_series_added",
|
||||||
|
}
|
||||||
|
b.ReportAllocs()
|
||||||
|
b.SetBytes(1)
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
for _, metric := range metrics {
|
||||||
|
if !isAutoMetric(metric) {
|
||||||
|
panic(fmt.Errorf("BUG: %q must be detected as auto metric", metric))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkScrapeWorkScrapeInternal(b *testing.B) {
|
func BenchmarkScrapeWorkScrapeInternal(b *testing.B) {
|
||||||
data := `
|
data := `
|
||||||
vm_tcplistener_accepts_total{name="http", addr=":80"} 1443
|
vm_tcplistener_accepts_total{name="http", addr=":80"} 1443
|
||||||
|
Loading…
Reference in New Issue
Block a user