mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
lib/protoparser/prometheus: properly parse metrics with exemplars
Examplars have been introduced in OpenMetrics - see https://github.com/OpenObservability/OpenMetrics/blob/master/OpenMetrics.md#exemplars-1 Previously VictoriaMetrics couldn't parse the following metric foo{bar="baz"} 123 # exemplar here This commit fixes this. Note that VictoriaMetrics ignores the exemplar as for now.
This commit is contained in:
parent
768fd8c3d9
commit
dad8b76a0e
3 changed files with 47 additions and 1 deletions
|
@ -19,6 +19,8 @@ See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/851
|
|||
* FEATURE: add remoteAddr to slow query log in order to simplify identifying the client that sends slow queries to VictoriaMetrics.
|
||||
Slow query logging is controlled with `-search.logSlowQueryDuration` command-line flag.
|
||||
|
||||
* BUGFIX: properly parse Prometheus metrics with [exemplars](https://github.com/OpenObservability/OpenMetrics/blob/master/OpenMetrics.md#exemplars-1) such as `foo 123 # {bar="baz"} 1`.
|
||||
|
||||
|
||||
# [v1.47.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.47.0)
|
||||
|
||||
|
|
|
@ -70,6 +70,14 @@ func (r *Row) reset() {
|
|||
r.Timestamp = 0
|
||||
}
|
||||
|
||||
func skipTrailingComment(s string) string {
|
||||
n := strings.IndexByte(s, '#')
|
||||
if n < 0 {
|
||||
return s
|
||||
}
|
||||
return s[:n]
|
||||
}
|
||||
|
||||
func skipLeadingWhitespace(s string) string {
|
||||
// Prometheus treats ' ' and '\t' as whitespace
|
||||
// according to https://github.com/prometheus/docs/blob/master/content/docs/instrumenting/exposition_formats.md#text-format-details
|
||||
|
@ -133,6 +141,7 @@ func (r *Row) unmarshal(s string, tagsPool []Tag, noEscapes bool) ([]Tag, error)
|
|||
return tagsPool, fmt.Errorf("metric cannot be empty")
|
||||
}
|
||||
s = skipLeadingWhitespace(s)
|
||||
s = skipTrailingComment(s)
|
||||
if len(s) == 0 {
|
||||
return tagsPool, fmt.Errorf("value cannot be empty")
|
||||
}
|
||||
|
@ -151,12 +160,16 @@ func (r *Row) unmarshal(s string, tagsPool []Tag, noEscapes bool) ([]Tag, error)
|
|||
if err != nil {
|
||||
return tagsPool, fmt.Errorf("cannot parse value %q: %w", s[:n], err)
|
||||
}
|
||||
r.Value = v
|
||||
s = skipLeadingWhitespace(s[n+1:])
|
||||
if len(s) == 0 {
|
||||
// There is no timestamp - just a whitespace after the value.
|
||||
return tagsPool, nil
|
||||
}
|
||||
ts, err := fastfloat.ParseInt64(s)
|
||||
if err != nil {
|
||||
return tagsPool, fmt.Errorf("cannot parse timestamp %q: %w", s, err)
|
||||
}
|
||||
r.Value = v
|
||||
r.Timestamp = ts
|
||||
return tagsPool, nil
|
||||
}
|
||||
|
|
|
@ -202,6 +202,37 @@ cassandra_token_ownership_ratio 78.9`, &Rows{
|
|||
}},
|
||||
})
|
||||
|
||||
// Exemplars - see https://github.com/OpenObservability/OpenMetrics/blob/master/OpenMetrics.md#exemplars-1
|
||||
f(`foo_bucket{le="10",a="#b"} 17 # {trace_id="oHg5SJ#YRHA0"} 9.8 1520879607.789
|
||||
abc 123 456#foobar
|
||||
foo 344#bar`, &Rows{
|
||||
Rows: []Row{
|
||||
{
|
||||
Metric: "foo_bucket",
|
||||
Tags: []Tag{
|
||||
{
|
||||
Key: "le",
|
||||
Value: "10",
|
||||
},
|
||||
{
|
||||
Key: "a",
|
||||
Value: "#b",
|
||||
},
|
||||
},
|
||||
Value: 17,
|
||||
},
|
||||
{
|
||||
Metric: "abc",
|
||||
Value: 123,
|
||||
Timestamp: 456,
|
||||
},
|
||||
{
|
||||
Metric: "foo",
|
||||
Value: 344,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Timestamp bigger than 1<<31
|
||||
f("aaa 1123 429496729600", &Rows{
|
||||
Rows: []Row{{
|
||||
|
|
Loading…
Reference in a new issue