-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Prometheus] Add unit tests for parsing metric families #36669
Changes from all commits
9f57d4a
b7b76eb
4a2c943
b5153df
1370449
a0b459c
c140872
82050d8
3d32656
76cf65e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -318,19 +318,25 @@ func (m *MetricFamily) GetMetric() []*OpenMetric { | |||||
} | ||||||
|
||||||
const ( | ||||||
suffixTotal = "_total" | ||||||
suffixGCount = "_gcount" | ||||||
suffixGSum = "_gsum" | ||||||
suffixCount = "_count" | ||||||
suffixSum = "_sum" | ||||||
suffixBucket = "_bucket" | ||||||
suffixTotal = "_total" | ||||||
suffixGCount = "_gcount" | ||||||
suffixGSum = "_gsum" | ||||||
suffixCount = "_count" | ||||||
suffixSum = "_sum" | ||||||
suffixBucket = "_bucket" | ||||||
suffixCreated = "_created" | ||||||
suffixInfo = "_info" | ||||||
) | ||||||
|
||||||
// Counters have _total suffix | ||||||
func isTotal(name string) bool { | ||||||
return strings.HasSuffix(name, suffixTotal) | ||||||
} | ||||||
|
||||||
func isCreated(name string) bool { | ||||||
return strings.HasSuffix(name, suffixCreated) | ||||||
} | ||||||
|
||||||
func isGCount(name string) bool { | ||||||
return strings.HasSuffix(name, suffixGCount) | ||||||
} | ||||||
|
@@ -351,7 +357,11 @@ func isBucket(name string) bool { | |||||
return strings.HasSuffix(name, suffixBucket) | ||||||
} | ||||||
|
||||||
func summaryMetricName(name string, s float64, qv string, lbls string, t *int64, summariesByName map[string]map[string]*OpenMetric) (string, *OpenMetric) { | ||||||
func isInfo(name string) bool { | ||||||
return strings.HasSuffix(name, suffixInfo) | ||||||
} | ||||||
|
||||||
func summaryMetricName(name string, s float64, qv string, lbls string, summariesByName map[string]map[string]*OpenMetric) (string, *OpenMetric) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Parameter |
||||||
var summary = &Summary{} | ||||||
var quantile = []*Quantile{} | ||||||
var quant = &Quantile{} | ||||||
|
@@ -360,10 +370,10 @@ func summaryMetricName(name string, s float64, qv string, lbls string, t *int64, | |||||
case isCount(name): | ||||||
u := uint64(s) | ||||||
summary.SampleCount = &u | ||||||
name = name[:len(name)-6] | ||||||
name = strings.TrimSuffix(name, suffixCount) | ||||||
case isSum(name): | ||||||
summary.SampleSum = &s | ||||||
name = name[:len(name)-4] | ||||||
name = strings.TrimSuffix(name, suffixSum) | ||||||
default: | ||||||
f, err := strconv.ParseFloat(qv, 64) | ||||||
if err != nil { | ||||||
|
@@ -373,8 +383,8 @@ func summaryMetricName(name string, s float64, qv string, lbls string, t *int64, | |||||
quant.Value = &s | ||||||
} | ||||||
|
||||||
_, k := summariesByName[name] | ||||||
if !k { | ||||||
_, ok := summariesByName[name] | ||||||
if !ok { | ||||||
summariesByName[name] = make(map[string]*OpenMetric) | ||||||
} | ||||||
metric, ok := summariesByName[name][lbls] | ||||||
|
@@ -392,7 +402,6 @@ func summaryMetricName(name string, s float64, qv string, lbls string, t *int64, | |||||
} else if quant.Quantile != nil { | ||||||
metric.Summary.Quantile = append(metric.Summary.Quantile, quant) | ||||||
} | ||||||
|
||||||
return name, metric | ||||||
} | ||||||
|
||||||
|
@@ -499,8 +508,6 @@ func ParseMetricFamilies(b []byte, contentType string, ts time.Time) ([]*MetricF | |||||
fam = &MetricFamily{Name: &s, Type: t} | ||||||
metricFamiliesByName[s] = fam | ||||||
} else { | ||||||
// In case the metric family already exists, we need to make sure the type is correctly defined | ||||||
// instead of being `unknown` like it was initialized for the other entry types (help and unit). | ||||||
fam.Type = t | ||||||
} | ||||||
mt = t | ||||||
|
@@ -511,21 +518,23 @@ func ParseMetricFamilies(b []byte, contentType string, ts time.Time) ([]*MetricF | |||||
h := string(t) | ||||||
_, ok = metricFamiliesByName[s] | ||||||
if !ok { | ||||||
fam = &MetricFamily{Name: &s, Help: &h, Type: textparse.MetricTypeUnknown} | ||||||
fam = &MetricFamily{Name: &s, Help: &h} | ||||||
metricFamiliesByName[s] = fam | ||||||
} else { | ||||||
fam.Help = &h | ||||||
} | ||||||
fam.Help = &h | ||||||
continue | ||||||
case textparse.EntryUnit: | ||||||
buf, t := parser.Unit() | ||||||
s := string(buf) | ||||||
u := string(t) | ||||||
_, ok = metricFamiliesByName[s] | ||||||
if !ok { | ||||||
fam = &MetricFamily{Name: &s, Unit: &u, Type: textparse.MetricTypeUnknown} | ||||||
fam = &MetricFamily{Name: &s, Unit: &u} | ||||||
metricFamiliesByName[string(buf)] = fam | ||||||
} else { | ||||||
fam.Unit = &u | ||||||
} | ||||||
fam.Unit = &u | ||||||
continue | ||||||
case textparse.EntryComment: | ||||||
continue | ||||||
|
@@ -577,49 +586,67 @@ func ParseMetricFamilies(b []byte, contentType string, ts time.Time) ([]*MetricF | |||||
var metric *OpenMetric | ||||||
|
||||||
metricName := lset.Get(labels.MetricName) | ||||||
var lookupMetricName string | ||||||
|
||||||
// lookupMetricName will have the suffixes removed | ||||||
lookupMetricName := metricName | ||||||
var exm *exemplar.Exemplar | ||||||
|
||||||
// Suffixes - https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#suffixes | ||||||
switch mt { | ||||||
case textparse.MetricTypeCounter: | ||||||
if contentType == OpenMetricsType && !isTotal(metricName) && !isCreated(metricName) { | ||||||
// Possible suffixes for counter in Open metrics are _created and _total. | ||||||
// Otherwise, ignore. | ||||||
// https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#counter-1 | ||||||
continue | ||||||
} | ||||||
|
||||||
var counter = &Counter{Value: &v} | ||||||
mn := lset.Get(labels.MetricName) | ||||||
metric = &OpenMetric{Name: &mn, Counter: counter, Label: labelPairs} | ||||||
if isTotal(metricName) && contentType == OpenMetricsType { // Remove suffix _total, get lookup metricname | ||||||
lookupMetricName = strings.TrimSuffix(metricName, suffixTotal) | ||||||
if contentType == OpenMetricsType { | ||||||
// Remove the two possible suffixes, _created and _total | ||||||
if isTotal(metricName) { | ||||||
lookupMetricName = strings.TrimSuffix(metricName, suffixTotal) | ||||||
} else { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because of this condition above |
||||||
lookupMetricName = strings.TrimSuffix(metricName, suffixCreated) | ||||||
} | ||||||
} else { | ||||||
lookupMetricName = metricName | ||||||
} | ||||||
case textparse.MetricTypeGauge: | ||||||
var gauge = &Gauge{Value: &v} | ||||||
metric = &OpenMetric{Name: &metricName, Gauge: gauge, Label: labelPairs} | ||||||
lookupMetricName = metricName | ||||||
//lookupMetricName = metricName | ||||||
case textparse.MetricTypeInfo: | ||||||
// Info only exists for Openmetrics. It must have the suffix _info | ||||||
if !isInfo(metricName) { | ||||||
continue | ||||||
} | ||||||
lookupMetricName = strings.TrimSuffix(metricName, suffixInfo) | ||||||
value := int64(v) | ||||||
var info = &Info{Value: &value} | ||||||
metric = &OpenMetric{Name: &metricName, Info: info, Label: labelPairs} | ||||||
lookupMetricName = metricName | ||||||
case textparse.MetricTypeSummary: | ||||||
lookupMetricName, metric = summaryMetricName(metricName, v, qv, lbls.String(), &t, summariesByName) | ||||||
lookupMetricName, metric = summaryMetricName(metricName, v, qv, lbls.String(), summariesByName) | ||||||
metric.Label = labelPairs | ||||||
if !isSum(metricName) { | ||||||
// Avoid registering the metric multiple times. | ||||||
continue | ||||||
} | ||||||
metricName = lookupMetricName | ||||||
case textparse.MetricTypeHistogram: | ||||||
if hasExemplar := parser.Exemplar(&e); hasExemplar { | ||||||
exm = &e | ||||||
} | ||||||
lookupMetricName, metric = histogramMetricName(metricName, v, qv, lbls.String(), &t, false, exm, histogramsByName) | ||||||
if metric == nil { // metric name does not have a suffix supported for the type histogram | ||||||
if metric == nil { | ||||||
continue | ||||||
} | ||||||
metric.Label = labelPairs | ||||||
if !isSum(metricName) { | ||||||
// Avoid registering the metric multiple times. | ||||||
continue | ||||||
} | ||||||
metricName = lookupMetricName | ||||||
case textparse.MetricTypeGaugeHistogram: | ||||||
if hasExemplar := parser.Exemplar(&e); hasExemplar { | ||||||
exm = &e | ||||||
|
@@ -631,29 +658,32 @@ func ParseMetricFamilies(b []byte, contentType string, ts time.Time) ([]*MetricF | |||||
metric.Label = labelPairs | ||||||
metric.Histogram.IsGaugeHistogram = true | ||||||
if !isGSum(metricName) { | ||||||
// Avoid registering the metric multiple times. | ||||||
continue | ||||||
} | ||||||
metricName = lookupMetricName | ||||||
case textparse.MetricTypeStateset: | ||||||
value := int64(v) | ||||||
var stateset = &Stateset{Value: &value} | ||||||
metric = &OpenMetric{Name: &metricName, Stateset: stateset, Label: labelPairs} | ||||||
lookupMetricName = metricName | ||||||
case textparse.MetricTypeUnknown: | ||||||
var unknown = &Unknown{Value: &v} | ||||||
metric = &OpenMetric{Name: &metricName, Unknown: unknown, Label: labelPairs} | ||||||
lookupMetricName = metricName | ||||||
default: | ||||||
lookupMetricName = metricName | ||||||
} | ||||||
|
||||||
fam, ok = metricFamiliesByName[lookupMetricName] | ||||||
if !ok { | ||||||
fam = &MetricFamily{Type: mt} | ||||||
metricFamiliesByName[lookupMetricName] = fam | ||||||
} | ||||||
// If the lookupMetricName is not in metricFamiliesByName, we check for metric name, in case | ||||||
// the removed suffix is part of the name. | ||||||
fam, ok = metricFamiliesByName[metricName] | ||||||
if !ok { | ||||||
// There is not any metadata for this metric. In this case, the name of the metric | ||||||
// will remain metricName instead of the possible modified lookupMetricName | ||||||
fam = &MetricFamily{Name: &metricName, Type: mt} | ||||||
metricFamiliesByName[metricName] = fam | ||||||
|
||||||
fam.Name = &metricName | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This line needed to be removed, because it was causing errors. Example: if we had this metric:
The metric would be renamed to |
||||||
} | ||||||
} | ||||||
|
||||||
if hasExemplar := parser.Exemplar(&e); hasExemplar && mt != textparse.MetricTypeHistogram && metric != nil { | ||||||
if !e.HasTs { | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to this, counter types MUST have the suffix
_total
. I had to fix this to pass the test.