Skip to content

Commit 6433bcf

Browse files
committed
Add the capability to lint MetricFamilies directly
Also, change all the `dto.MetricFamily` arguments to pointers to be more consistent with what we do in client_golang in general. Signed-off-by: beorn7 <[email protected]>
1 parent a3a5923 commit 6433bcf

File tree

1 file changed

+38
-25
lines changed

1 file changed

+38
-25
lines changed

prometheus/testutil/promlint/promlint.go

Lines changed: 38 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ import (
2929
// A Linter is a Prometheus metrics linter. It identifies issues with metric
3030
// names, types, and metadata, and reports them to the caller.
3131
type Linter struct {
32-
r io.Reader
32+
r io.Reader
33+
mfs []*dto.MetricFamily
3334
}
3435

3536
// A Problem is an issue detected by a Linter.
@@ -42,40 +43,52 @@ type Problem struct {
4243
}
4344

4445
// newProblem is helper function to create a Problem.
45-
func newProblem(mf dto.MetricFamily, text string) Problem {
46+
func newProblem(mf *dto.MetricFamily, text string) Problem {
4647
return Problem{
4748
Metric: mf.GetName(),
4849
Text: text,
4950
}
5051
}
5152

52-
// New creates a new Linter that reads an input stream of Prometheus metrics.
53-
// Only the Prometheus text exposition format is supported.
53+
// New creates a new Linter that reads an input stream of Prometheus metrics in
54+
// the Prometheus text exposition format.
5455
func New(r io.Reader) *Linter {
5556
return &Linter{
5657
r: r,
5758
}
5859
}
5960

61+
// NewWithMetricFamilies creates a new Linter that reads from a slice of
62+
// MetricFamily protobuf messages.
63+
func NewWithMetricFamilies(mfs []*dto.MetricFamily) *Linter {
64+
return &Linter{
65+
mfs: mfs,
66+
}
67+
}
68+
6069
// Lint performs a linting pass, returning a slice of Problems indicating any
61-
// issues found in the metrics stream. The slice is sorted by metric name
70+
// issues found in the metrics stream. The slice is sorted by metric name
6271
// and issue description.
6372
func (l *Linter) Lint() ([]Problem, error) {
64-
// TODO(mdlayher): support for protobuf exposition format?
65-
d := expfmt.NewDecoder(l.r, expfmt.FmtText)
66-
6773
var problems []Problem
6874

69-
var mf dto.MetricFamily
70-
for {
71-
if err := d.Decode(&mf); err != nil {
72-
if err == io.EOF {
73-
break
75+
if l.r != nil {
76+
d := expfmt.NewDecoder(l.r, expfmt.FmtText)
77+
78+
mf := &dto.MetricFamily{}
79+
for {
80+
if err := d.Decode(mf); err != nil {
81+
if err == io.EOF {
82+
break
83+
}
84+
85+
return nil, err
7486
}
7587

76-
return nil, err
88+
problems = append(problems, lint(mf)...)
7789
}
78-
90+
}
91+
for _, mf := range l.mfs {
7992
problems = append(problems, lint(mf)...)
8093
}
8194

@@ -91,8 +104,8 @@ func (l *Linter) Lint() ([]Problem, error) {
91104
}
92105

93106
// lint is the entry point for linting a single metric.
94-
func lint(mf dto.MetricFamily) []Problem {
95-
fns := []func(mf dto.MetricFamily) []Problem{
107+
func lint(mf *dto.MetricFamily) []Problem {
108+
fns := []func(mf *dto.MetricFamily) []Problem{
96109
lintHelp,
97110
lintMetricUnits,
98111
lintCounter,
@@ -113,7 +126,7 @@ func lint(mf dto.MetricFamily) []Problem {
113126
}
114127

115128
// lintHelp detects issues related to the help text for a metric.
116-
func lintHelp(mf dto.MetricFamily) []Problem {
129+
func lintHelp(mf *dto.MetricFamily) []Problem {
117130
var problems []Problem
118131

119132
// Expect all metrics to have help text available.
@@ -125,7 +138,7 @@ func lintHelp(mf dto.MetricFamily) []Problem {
125138
}
126139

127140
// lintMetricUnits detects issues with metric unit names.
128-
func lintMetricUnits(mf dto.MetricFamily) []Problem {
141+
func lintMetricUnits(mf *dto.MetricFamily) []Problem {
129142
var problems []Problem
130143

131144
unit, base, ok := metricUnits(*mf.Name)
@@ -146,7 +159,7 @@ func lintMetricUnits(mf dto.MetricFamily) []Problem {
146159

147160
// lintCounter detects issues specific to counters, as well as patterns that should
148161
// only be used with counters.
149-
func lintCounter(mf dto.MetricFamily) []Problem {
162+
func lintCounter(mf *dto.MetricFamily) []Problem {
150163
var problems []Problem
151164

152165
isCounter := mf.GetType() == dto.MetricType_COUNTER
@@ -165,7 +178,7 @@ func lintCounter(mf dto.MetricFamily) []Problem {
165178

166179
// lintHistogramSummaryReserved detects when other types of metrics use names or labels
167180
// reserved for use by histograms and/or summaries.
168-
func lintHistogramSummaryReserved(mf dto.MetricFamily) []Problem {
181+
func lintHistogramSummaryReserved(mf *dto.MetricFamily) []Problem {
169182
// These rules do not apply to untyped metrics.
170183
t := mf.GetType()
171184
if t == dto.MetricType_UNTYPED {
@@ -206,7 +219,7 @@ func lintHistogramSummaryReserved(mf dto.MetricFamily) []Problem {
206219
}
207220

208221
// lintMetricTypeInName detects when metric types are included in the metric name.
209-
func lintMetricTypeInName(mf dto.MetricFamily) []Problem {
222+
func lintMetricTypeInName(mf *dto.MetricFamily) []Problem {
210223
var problems []Problem
211224
n := strings.ToLower(mf.GetName())
212225

@@ -224,7 +237,7 @@ func lintMetricTypeInName(mf dto.MetricFamily) []Problem {
224237
}
225238

226239
// lintReservedChars detects colons in metric names.
227-
func lintReservedChars(mf dto.MetricFamily) []Problem {
240+
func lintReservedChars(mf *dto.MetricFamily) []Problem {
228241
var problems []Problem
229242
if strings.Contains(mf.GetName(), ":") {
230243
problems = append(problems, newProblem(mf, "metric names should not contain ':'"))
@@ -235,7 +248,7 @@ func lintReservedChars(mf dto.MetricFamily) []Problem {
235248
var camelCase = regexp.MustCompile(`[a-z][A-Z]`)
236249

237250
// lintCamelCase detects metric names and label names written in camelCase.
238-
func lintCamelCase(mf dto.MetricFamily) []Problem {
251+
func lintCamelCase(mf *dto.MetricFamily) []Problem {
239252
var problems []Problem
240253
if camelCase.FindString(mf.GetName()) != "" {
241254
problems = append(problems, newProblem(mf, "metric names should be written in 'snake_case' not 'camelCase'"))
@@ -252,7 +265,7 @@ func lintCamelCase(mf dto.MetricFamily) []Problem {
252265
}
253266

254267
// lintUnitAbbreviations detects abbreviated units in the metric name.
255-
func lintUnitAbbreviations(mf dto.MetricFamily) []Problem {
268+
func lintUnitAbbreviations(mf *dto.MetricFamily) []Problem {
256269
var problems []Problem
257270
n := strings.ToLower(mf.GetName())
258271
for _, s := range unitAbbreviations {

0 commit comments

Comments
 (0)