Factor out label compare and store

Signed-off-by: György Krajcsovits <gyorgy.krajcsovits@grafana.com>
pull/14978/head
György Krajcsovits 2024-10-08 10:12:25 +02:00
parent 16f28be713
commit e931587bf8
2 changed files with 89 additions and 34 deletions

View File

@ -70,9 +70,6 @@ type NHCBParser struct {
tempNHCB convertnhcb.TempHistogram
isCollationInProgress bool
// Remembers the last native histogram name so we can ignore
// conversions to NHCB when the name is the same.
lastNativeHistLabels labels.Labels
// Remembers the last base histogram metric name (assuming it's
// a classic histogram) so we can tell if the next float series
// is part of the same classic histogram.
@ -159,34 +156,7 @@ func (p *NHCBParser) Next() (Entry, error) {
p.metricString = p.parser.Metric(&p.lset)
p.ct = p.parser.CreatedTimestamp()
// Check the label set to see if we can continue or need to emit the NHCB.
shouldInsertNHCB := false
if len(p.lastBaseHistLabels) > 0 {
InnerCompare:
for _, l := range p.lset {
if l.Name == labels.MetricName {
baseName := convertnhcb.GetHistogramMetricBaseName(l.Value)
if baseName != p.lastBaseHistLabels.Get(labels.MetricName) {
p.storeBaseLabels()
shouldInsertNHCB = true
break InnerCompare
}
continue InnerCompare
}
if l.Name == labels.BucketLabel {
// Ignore.
continue InnerCompare
}
if l.Value != p.lastBaseHistLabels.Get(l.Name) {
// Different label value.
p.storeBaseLabels()
shouldInsertNHCB = true
break InnerCompare
}
}
} else {
p.storeBaseLabels()
}
if shouldInsertNHCB && p.processNHCB() {
if p.compareLabels() && p.processNHCB() {
p.entry = et
return EntryHistogram, nil
}
@ -198,7 +168,6 @@ func (p *NHCBParser) Next() (Entry, error) {
p.bytes, p.ts, p.h, p.fh = p.parser.Histogram()
p.metricString = p.parser.Metric(&p.lset)
p.ct = p.parser.CreatedTimestamp()
p.lastNativeHistLabels.CopyFrom(p.lset)
case EntryType:
p.bName, p.typ = p.parser.Type()
}
@ -209,6 +178,53 @@ func (p *NHCBParser) Next() (Entry, error) {
return et, err
}
// Return true if labels have changed and we should emit the NHCB.
// Update the stored labels if the labels have changed.
func (p *NHCBParser) compareLabels() bool {
// Collection not in progress.
if p.lastBaseHistLabels.IsEmpty() {
if p.typ == model.MetricTypeHistogram {
p.storeBaseLabels()
}
return false
}
if p.typ != model.MetricTypeHistogram {
// Different metric type, emit the NHCB.
p.lastBaseHistLabels = labels.EmptyLabels()
return true
}
// Compare the labels.
for _, l := range p.lset {
if l.Name == labels.MetricName {
baseName := convertnhcb.GetHistogramMetricBaseName(l.Value)
if baseName != p.lastBaseHistLabels.Get(labels.MetricName) {
if p.typ == model.MetricTypeHistogram {
p.storeBaseLabels()
} else {
p.lastBaseHistLabels = labels.EmptyLabels()
}
return true
}
continue
}
if l.Name == labels.BucketLabel {
// Ignore.
continue
}
if l.Value != p.lastBaseHistLabels.Get(l.Name) {
// Different label value.
if p.typ == model.MetricTypeHistogram {
p.storeBaseLabels()
} else {
p.lastBaseHistLabels = labels.EmptyLabels()
}
return true
}
}
return false
}
// Save the label set of the classic histogram without suffix and bucket `le` label.
func (p *NHCBParser) storeBaseLabels() {
builder := labels.Builder{}

View File

@ -282,14 +282,14 @@ foobar{quantile="0.99"} 150.1`
v: 17,
lset: labels.FromStrings("__name__", "foo_total"),
t: int64p(1520879607789),
// TODO(krajorama) e:es: []exemplar.Exemplar{{Labels: labels.FromStrings("id", "counter-test"), Value: 5}},
//es: []exemplar.Exemplar{{Labels: labels.FromStrings("id", "counter-test"), Value: 5}},
ct: int64p(1520872607123),
}, {
m: `foo_total{a="b"}`,
v: 17.0,
lset: labels.FromStrings("__name__", "foo_total", "a", "b"),
t: int64p(1520879607789),
// TODO(krajorama) e:es: []exemplar.Exemplar{{Labels: labels.FromStrings("id", "counter-test"), Value: 5}},
//es: []exemplar.Exemplar{{Labels: labels.FromStrings("id", "counter-test"), Value: 5}},
ct: int64p(1520872607123),
}, {
m: "bar",
@ -500,3 +500,42 @@ something_created{a="b"} 1520430002
got := testParse(t, p)
requireEntries(t, exp, got)
}
func TestNhcbParserExemplarOnOpenMetricsParser(t *testing.T) {
// The input is taken originally from TestOpenMetricsParse, with additional tests for the NHCBParser.
input := `# HELP foo Counter with and without labels to certify CT is parsed for both cases
# TYPE foo counter
foo_total 17.0 1520879607.789 # {id="counter-test"} 5
foo_created 1520872607.123
# EOF
`
exp := []parsedEntry{
{
m: "foo",
help: "Counter with and without labels to certify CT is parsed for both cases",
}, {
m: "foo",
typ: model.MetricTypeCounter,
}, {
m: "foo_total",
v: 17,
lset: labels.FromStrings("__name__", "foo_total"),
t: int64p(1520879607789),
//es: []exemplar.Exemplar{{Labels: labels.FromStrings("id", "counter-test"), Value: 5}},
ct: int64p(1520872607123),
// }, {
// m: `foo_total{a="b"}`,
// v: 17.0,
// lset: labels.FromStrings("__name__", "foo_total", "a", "b"),
// t: int64p(1520879607789),
// es: []exemplar.Exemplar{{Labels: labels.FromStrings("id", "counter-test"), Value: 5}},
// ct: int64p(1520872607123),
},
}
p := NewOpenMetricsParser([]byte(input), labels.NewSymbolTable(), WithOMParserCTSeriesSkipped())
p = NewNHCBParser(p, false)
got := testParse(t, p)
requireEntries(t, exp, got)
}