From f4969a624dca5430a75976e3d157fee8c09878fb Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Mon, 1 Mar 2021 17:15:52 +0200 Subject: [PATCH] lib/protoparser/graphite: fix parsing of a Graphite line with empty tags such as `foo; 1 2` See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1100 --- docs/CHANGELOG.md | 1 + lib/protoparser/graphite/parser.go | 23 +++++++++--------- lib/protoparser/graphite/parser_test.go | 32 +++++++++++++++++++------ 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index a6972c5df..2a48b557b 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -30,6 +30,7 @@ * BUGFIX: fix `http: superfluous response.WriteHeader call` issue. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1078 * BUGFIX: fix arm64 builds due to the issue in `github.com/golang/snappy`. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1074 * BUGFIX: fix `index out of range [1024819115206086200] with length 27` panic, which could occur when `1e-9` value is passed to VictoriaMetrics histogram. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1096 +* BUGFIX: fix parsing for Graphite line with empty tags such as `foo; 123 456`. See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1100 # [v1.54.1](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.54.1) diff --git a/lib/protoparser/graphite/parser.go b/lib/protoparser/graphite/parser.go index c2e20b3d5..5c1643777 100644 --- a/lib/protoparser/graphite/parser.go +++ b/lib/protoparser/graphite/parser.go @@ -71,7 +71,7 @@ func (r *Row) UnmarshalMetricAndTags(s string, tagsPool []Tag) ([]Tag, error) { var err error tagsPool, err = unmarshalTags(tagsPool, s[n+1:]) if err != nil { - return tagsPool, fmt.Errorf("cannot umarshal tags: %w", err) + return tagsPool, fmt.Errorf("cannot unmarshal tags: %w", err) } tags := tagsPool[tagsStart:] r.Tags = tags[:len(tags):len(tags)] @@ -171,18 +171,14 @@ func unmarshalTags(dst []Tag, s string) ([]Tag, error) { n := strings.IndexByte(s, ';') if n < 0 { // The last tag found - if err := tag.unmarshal(s); err != nil { - return dst[:len(dst)-1], err - } + tag.unmarshal(s) if len(tag.Key) == 0 || len(tag.Value) == 0 { // Skip empty tag dst = dst[:len(dst)-1] } return dst, nil } - if err := tag.unmarshal(s[:n]); err != nil { - return dst[:len(dst)-1], err - } + tag.unmarshal(s[:n]) s = s[n+1:] if len(tag.Key) == 0 || len(tag.Value) == 0 { // Skip empty tag @@ -202,13 +198,16 @@ func (t *Tag) reset() { t.Value = "" } -func (t *Tag) unmarshal(s string) error { +func (t *Tag) unmarshal(s string) { t.reset() n := strings.IndexByte(s, '=') if n < 0 { - return fmt.Errorf("missing tag value for %q", s) + // Empty tag value. + // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1100 + t.Key = s + t.Value = s[len(s):] + } else { + t.Key = s[:n] + t.Value = s[n+1:] } - t.Key = s[:n] - t.Value = s[n+1:] - return nil } diff --git a/lib/protoparser/graphite/parser_test.go b/lib/protoparser/graphite/parser_test.go index b04314f1a..85e2cb76e 100644 --- a/lib/protoparser/graphite/parser_test.go +++ b/lib/protoparser/graphite/parser_test.go @@ -19,7 +19,6 @@ func TestUnmarshalMetricAndTagsFailure(t *testing.T) { f("") f(";foo=bar") f(" ") - f("foo;bar") f("foo ;bar=baz") f("f oo;bar=baz") f("foo;bar=baz ") @@ -80,12 +79,6 @@ func TestRowsUnmarshalFailure(t *testing.T) { // Missing value f("aaa") - // missing tag - f("aa; 12 34") - - // missing tag value - f("aa;bb 23 34") - // unexpected space in tag value // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/99 f("s;tag1=aaa1;tag2=bb b2;tag3=ccc3 1") @@ -187,6 +180,31 @@ func TestRowsUnmarshalSuccess(t *testing.T) { }}, }) // Empty tags + // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1100 + f("foo; 1", &Rows{ + Rows: []Row{{ + Metric: "foo", + Tags: []Tag{}, + Value: 1, + }}, + }) + f("foo; 1 2", &Rows{ + Rows: []Row{{ + Metric: "foo", + Tags: []Tag{}, + Value: 1, + Timestamp: 2, + }}, + }) + // Empty tag name or value + f("foo;bar 1 2", &Rows{ + Rows: []Row{{ + Metric: "foo", + Tags: []Tag{}, + Value: 1, + Timestamp: 2, + }}, + }) f("foo;bar=baz;aa=;x=y;=z 1 2", &Rows{ Rows: []Row{{ Metric: "foo",