diff --git a/lib/protoparser/opentsdb/parser.go b/lib/protoparser/opentsdb/parser.go index a63ccda30..7f8a43f8e 100644 --- a/lib/protoparser/opentsdb/parser.go +++ b/lib/protoparser/opentsdb/parser.go @@ -84,20 +84,24 @@ func (r *Row) unmarshal(s string, tagsPool []Tag) ([]Tag, error) { tail = trimLeadingSpaces(tail[n+1:]) n = strings.IndexByte(tail, ' ') if n < 0 { - return tagsPool, fmt.Errorf("cannot find whitespace between value and the first tag in %q", s) + // see https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3290 + n = len(tail) } v, err := fastfloat.Parse(tail[:n]) if err != nil { return tagsPool, fmt.Errorf("cannot parse value from %q: %w", tail[:n], err) } r.Value = v - tagsStart := len(tagsPool) - tagsPool, err = unmarshalTags(tagsPool, tail[n+1:]) - if err != nil { - return tagsPool, fmt.Errorf("cannot unmarshal tags in %q: %w", s, err) + if len(tail) > n { + tagsStart := len(tagsPool) + tagsPool, err = unmarshalTags(tagsPool, tail[n+1:]) + if err != nil { + return tagsPool, fmt.Errorf("cannot unmarshal tags in %q: %w", s, err) + } + tags := tagsPool[tagsStart:] + r.Tags = tags[:len(tags):len(tags)] } - tags := tagsPool[tagsStart:] - r.Tags = tags[:len(tags):len(tags)] + return tagsPool, nil } diff --git a/lib/protoparser/opentsdb/parser_test.go b/lib/protoparser/opentsdb/parser_test.go index d2e739f90..7e7c435c9 100644 --- a/lib/protoparser/opentsdb/parser_test.go +++ b/lib/protoparser/opentsdb/parser_test.go @@ -37,9 +37,6 @@ func TestRowsUnmarshalFailure(t *testing.T) { f("put aaa timestamp") f("put foobar 3df4 -123456 a=b") - // Missing first tag - f("put aaa 123 43") - // Invalid value f("put aaa 123 invalid-value") f("put foobar 789 -123foo456 a=b") @@ -104,6 +101,14 @@ func TestRowsUnmarshalSuccess(t *testing.T) { }, }}, }) + // No tags + f("put foobar 789 -123.456", &Rows{ + Rows: []Row{{ + Metric: "foobar", + Value: -123.456, + Timestamp: 789, + }}, + }) // Fractional timestamp that is supported by Akumuli. f("put foobar 789.4 -123.456 a=b", &Rows{ Rows: []Row{{