app/vmselect: do not export NaN values for stale metrics at /federate endpoint

Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3185
This commit is contained in:
Aliaksandr Valialkin 2022-10-01 19:47:35 +03:00
parent dd46521676
commit 4ef2d46b8b
No known key found for this signature in database
GPG key ID: A72BEC6CD3D0DED1
4 changed files with 68 additions and 31 deletions

View file

@ -54,6 +54,9 @@ func (bw *Writer) reset() {
// Write writes p to bw. // Write writes p to bw.
func (bw *Writer) Write(p []byte) (int, error) { func (bw *Writer) Write(p []byte) (int, error) {
if len(p) == 0 {
return 0, nil
}
bw.lock.Lock() bw.lock.Lock()
defer bw.lock.Unlock() defer bw.lock.Unlock()
if bw.err != nil { if bw.err != nil {

View file

@ -1,4 +1,6 @@
{% import ( {% import (
"math"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/netstorage" "github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/netstorage"
) %} ) %}
@ -7,10 +9,25 @@
// Federate writes rs in /federate format. // Federate writes rs in /federate format.
// See https://prometheus.io/docs/prometheus/latest/federation/ // See https://prometheus.io/docs/prometheus/latest/federation/
{% func Federate(rs *netstorage.Result) %} {% func Federate(rs *netstorage.Result) %}
{% if len(rs.Timestamps) == 0 || len(rs.Values) == 0 %}{% return %}{% endif %} {% code
values := rs.Values
timestamps := rs.Timestamps
%}
{% if len(timestamps) == 0 || len(values) == 0 %}{% return %}{% endif %}
{% code
lastValue := values[len(values)-1]
%}
{% if math.IsNaN(lastValue) %}
{% comment %}
This is most likely a staleness marker.
Return nothing after the staleness marker.
See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3185
{% endcomment %}
{% return %}
{% endif %}
{%= prometheusMetricName(&rs.MetricName) %}{% space %} {%= prometheusMetricName(&rs.MetricName) %}{% space %}
{%f= rs.Values[len(rs.Values)-1] %}{% space %} {%f= lastValue %}{% space %}
{%dl= rs.Timestamps[len(rs.Timestamps)-1] %}{% newline %} {%dl= timestamps[len(timestamps)-1] %}{% newline %}
{% endfunc %} {% endfunc %}
{% endstripspace %} {% endstripspace %}

View file

@ -6,70 +6,85 @@ package prometheus
//line app/vmselect/prometheus/federate.qtpl:1 //line app/vmselect/prometheus/federate.qtpl:1
import ( import (
"math"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/netstorage" "github.com/VictoriaMetrics/VictoriaMetrics/app/vmselect/netstorage"
) )
// Federate writes rs in /federate format.// See https://prometheus.io/docs/prometheus/latest/federation/ // Federate writes rs in /federate format.// See https://prometheus.io/docs/prometheus/latest/federation/
//line app/vmselect/prometheus/federate.qtpl:9 //line app/vmselect/prometheus/federate.qtpl:11
import ( import (
qtio422016 "io" qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate" qt422016 "github.com/valyala/quicktemplate"
) )
//line app/vmselect/prometheus/federate.qtpl:9 //line app/vmselect/prometheus/federate.qtpl:11
var ( var (
_ = qtio422016.Copy _ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer _ = qt422016.AcquireByteBuffer
) )
//line app/vmselect/prometheus/federate.qtpl:9 //line app/vmselect/prometheus/federate.qtpl:11
func StreamFederate(qw422016 *qt422016.Writer, rs *netstorage.Result) { func StreamFederate(qw422016 *qt422016.Writer, rs *netstorage.Result) {
//line app/vmselect/prometheus/federate.qtpl:10 //line app/vmselect/prometheus/federate.qtpl:13
if len(rs.Timestamps) == 0 || len(rs.Values) == 0 { values := rs.Values
//line app/vmselect/prometheus/federate.qtpl:10 timestamps := rs.Timestamps
//line app/vmselect/prometheus/federate.qtpl:16
if len(timestamps) == 0 || len(values) == 0 {
//line app/vmselect/prometheus/federate.qtpl:16
return return
//line app/vmselect/prometheus/federate.qtpl:10 //line app/vmselect/prometheus/federate.qtpl:16
} }
//line app/vmselect/prometheus/federate.qtpl:11 //line app/vmselect/prometheus/federate.qtpl:18
lastValue := values[len(values)-1]
//line app/vmselect/prometheus/federate.qtpl:20
if math.IsNaN(lastValue) {
//line app/vmselect/prometheus/federate.qtpl:26
return
//line app/vmselect/prometheus/federate.qtpl:27
}
//line app/vmselect/prometheus/federate.qtpl:28
streamprometheusMetricName(qw422016, &rs.MetricName) streamprometheusMetricName(qw422016, &rs.MetricName)
//line app/vmselect/prometheus/federate.qtpl:11 //line app/vmselect/prometheus/federate.qtpl:28
qw422016.N().S(` `) qw422016.N().S(` `)
//line app/vmselect/prometheus/federate.qtpl:12 //line app/vmselect/prometheus/federate.qtpl:29
qw422016.N().F(rs.Values[len(rs.Values)-1]) qw422016.N().F(lastValue)
//line app/vmselect/prometheus/federate.qtpl:12 //line app/vmselect/prometheus/federate.qtpl:29
qw422016.N().S(` `) qw422016.N().S(` `)
//line app/vmselect/prometheus/federate.qtpl:13 //line app/vmselect/prometheus/federate.qtpl:30
qw422016.N().DL(rs.Timestamps[len(rs.Timestamps)-1]) qw422016.N().DL(timestamps[len(timestamps)-1])
//line app/vmselect/prometheus/federate.qtpl:13 //line app/vmselect/prometheus/federate.qtpl:30
qw422016.N().S(` qw422016.N().S(`
`) `)
//line app/vmselect/prometheus/federate.qtpl:14 //line app/vmselect/prometheus/federate.qtpl:31
} }
//line app/vmselect/prometheus/federate.qtpl:14 //line app/vmselect/prometheus/federate.qtpl:31
func WriteFederate(qq422016 qtio422016.Writer, rs *netstorage.Result) { func WriteFederate(qq422016 qtio422016.Writer, rs *netstorage.Result) {
//line app/vmselect/prometheus/federate.qtpl:14 //line app/vmselect/prometheus/federate.qtpl:31
qw422016 := qt422016.AcquireWriter(qq422016) qw422016 := qt422016.AcquireWriter(qq422016)
//line app/vmselect/prometheus/federate.qtpl:14 //line app/vmselect/prometheus/federate.qtpl:31
StreamFederate(qw422016, rs) StreamFederate(qw422016, rs)
//line app/vmselect/prometheus/federate.qtpl:14 //line app/vmselect/prometheus/federate.qtpl:31
qt422016.ReleaseWriter(qw422016) qt422016.ReleaseWriter(qw422016)
//line app/vmselect/prometheus/federate.qtpl:14 //line app/vmselect/prometheus/federate.qtpl:31
} }
//line app/vmselect/prometheus/federate.qtpl:14 //line app/vmselect/prometheus/federate.qtpl:31
func Federate(rs *netstorage.Result) string { func Federate(rs *netstorage.Result) string {
//line app/vmselect/prometheus/federate.qtpl:14 //line app/vmselect/prometheus/federate.qtpl:31
qb422016 := qt422016.AcquireByteBuffer() qb422016 := qt422016.AcquireByteBuffer()
//line app/vmselect/prometheus/federate.qtpl:14 //line app/vmselect/prometheus/federate.qtpl:31
WriteFederate(qb422016, rs) WriteFederate(qb422016, rs)
//line app/vmselect/prometheus/federate.qtpl:14 //line app/vmselect/prometheus/federate.qtpl:31
qs422016 := string(qb422016.B) qs422016 := string(qb422016.B)
//line app/vmselect/prometheus/federate.qtpl:14 //line app/vmselect/prometheus/federate.qtpl:31
qt422016.ReleaseByteBuffer(qb422016) qt422016.ReleaseByteBuffer(qb422016)
//line app/vmselect/prometheus/federate.qtpl:14 //line app/vmselect/prometheus/federate.qtpl:31
return qs422016 return qs422016
//line app/vmselect/prometheus/federate.qtpl:14 //line app/vmselect/prometheus/federate.qtpl:31
} }

View file

@ -17,6 +17,8 @@ The following tip changes can be tested by building VictoriaMetrics components f
* FEATURE: expose `vmagent_remotewrite_queues` metric and use it in alerting rules in order to improve the detection of remote storage connection saturation. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/2871). * FEATURE: expose `vmagent_remotewrite_queues` metric and use it in alerting rules in order to improve the detection of remote storage connection saturation. See [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/2871).
* BUGFIX: do not export stale metrics via [/federate api](https://docs.victoriametrics.com/#federation) after the staleness markers. Previously such metrics were exported with `NaN` values. this could break some setups. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3185).
## [v1.79.3](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.79.3) ## [v1.79.3](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.79.3)