Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions expfmt/text_parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ func (p *TextParser) reset(in io.Reader) {
// start of a line (or whitespace leading up to it).
func (p *TextParser) startOfLine() stateFn {
p.lineCount++
p.currentMetric = nil
p.currentMetricIsInsideBraces = false
p.currentMetricInsideBracesIsPresent = false
if p.skipBlankTab(); p.err != nil {
Expand Down Expand Up @@ -339,12 +340,11 @@ func (p *TextParser) startLabelName() stateFn {
return nil // Unexpected end of input.
}
if p.currentByte == '}' {
if p.currentMF == nil {
if p.currentMetric == nil {
// The closing brace was reached before any metric name was read,
// e.g. for the input "{}". There is no metric to attach labels to,
// so this is a malformed exposition. This mirrors the guard in
// startLabelValue. currentMF (not currentMetric) is checked because
// reset only clears currentMF between parses.
// startLabelValue. currentMetric is cleared at the start of each line.
p.parseError("invalid metric name")
p.currentLabelPairs = nil
return nil
Expand Down Expand Up @@ -495,7 +495,7 @@ func (p *TextParser) startLabelValue() stateFn {
return p.startLabelName

case '}':
if p.currentMF == nil {
if p.currentMetric == nil {
p.parseError("invalid metric name")
return nil
}
Expand Down
32 changes: 32 additions & 0 deletions expfmt/text_parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1378,6 +1378,38 @@ func TestTextParseError(t *testing.T) {
testTextParseError(t)
}

func TestTextParseMissingMetricName(t *testing.T) {
for _, scheme := range []model.ValidationScheme{model.LegacyValidation, model.UTF8Validation} {
t.Run(scheme.String(), func(t *testing.T) {
for _, prefix := range []string{
"",
"#TYPE A000000 summArY\n",
"# TYPE metric histogram\n",
"# HELP metric Help text.\n",
"metric 1\n",
"{\"metric\"} 1\n",
} {
for _, sample := range []string{"{}", "{} 2\n", "{label=\"value\"} 2\n", "{label=\"value\",} 2\n"} {
t.Run(prefix+sample, func(t *testing.T) {
p := NewTextParser(scheme)
for range 2 {
_, err := p.TextToMetricFamilies(strings.NewReader(prefix + sample))
var parseErr ParseError
if !errors.As(err, &parseErr) || parseErr.Msg != "invalid metric name" || parseErr.Line != strings.Count(prefix, "\n")+1 {
t.Fatalf("expected invalid metric name on the sample line, got %v", err)
}
// Exercise reuse after both malformed input and a valid sample.
if _, err := p.TextToMetricFamilies(strings.NewReader("valid 1\n")); err != nil {
t.Fatalf("parsing valid sample after malformed input: %v", err)
}
}
})
}
}
})
}
}

func BenchmarkParseError(b *testing.B) {
for i := 0; i < b.N; i++ {
testTextParseError(b)
Expand Down
Loading