@@ -29,7 +29,8 @@ import (
29
29
// A Linter is a Prometheus metrics linter. It identifies issues with metric
30
30
// names, types, and metadata, and reports them to the caller.
31
31
type Linter struct {
32
- r io.Reader
32
+ r io.Reader
33
+ mfs []* dto.MetricFamily
33
34
}
34
35
35
36
// A Problem is an issue detected by a Linter.
@@ -42,40 +43,52 @@ type Problem struct {
42
43
}
43
44
44
45
// 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 {
46
47
return Problem {
47
48
Metric : mf .GetName (),
48
49
Text : text ,
49
50
}
50
51
}
51
52
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.
54
55
func New (r io.Reader ) * Linter {
55
56
return & Linter {
56
57
r : r ,
57
58
}
58
59
}
59
60
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
+
60
69
// 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
62
71
// and issue description.
63
72
func (l * Linter ) Lint () ([]Problem , error ) {
64
- // TODO(mdlayher): support for protobuf exposition format?
65
- d := expfmt .NewDecoder (l .r , expfmt .FmtText )
66
-
67
73
var problems []Problem
68
74
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
74
86
}
75
87
76
- return nil , err
88
+ problems = append ( problems , lint ( mf ) ... )
77
89
}
78
-
90
+ }
91
+ for _ , mf := range l .mfs {
79
92
problems = append (problems , lint (mf )... )
80
93
}
81
94
@@ -91,8 +104,8 @@ func (l *Linter) Lint() ([]Problem, error) {
91
104
}
92
105
93
106
// 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 {
96
109
lintHelp ,
97
110
lintMetricUnits ,
98
111
lintCounter ,
@@ -113,7 +126,7 @@ func lint(mf dto.MetricFamily) []Problem {
113
126
}
114
127
115
128
// 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 {
117
130
var problems []Problem
118
131
119
132
// Expect all metrics to have help text available.
@@ -125,7 +138,7 @@ func lintHelp(mf dto.MetricFamily) []Problem {
125
138
}
126
139
127
140
// lintMetricUnits detects issues with metric unit names.
128
- func lintMetricUnits (mf dto.MetricFamily ) []Problem {
141
+ func lintMetricUnits (mf * dto.MetricFamily ) []Problem {
129
142
var problems []Problem
130
143
131
144
unit , base , ok := metricUnits (* mf .Name )
@@ -146,7 +159,7 @@ func lintMetricUnits(mf dto.MetricFamily) []Problem {
146
159
147
160
// lintCounter detects issues specific to counters, as well as patterns that should
148
161
// only be used with counters.
149
- func lintCounter (mf dto.MetricFamily ) []Problem {
162
+ func lintCounter (mf * dto.MetricFamily ) []Problem {
150
163
var problems []Problem
151
164
152
165
isCounter := mf .GetType () == dto .MetricType_COUNTER
@@ -165,7 +178,7 @@ func lintCounter(mf dto.MetricFamily) []Problem {
165
178
166
179
// lintHistogramSummaryReserved detects when other types of metrics use names or labels
167
180
// reserved for use by histograms and/or summaries.
168
- func lintHistogramSummaryReserved (mf dto.MetricFamily ) []Problem {
181
+ func lintHistogramSummaryReserved (mf * dto.MetricFamily ) []Problem {
169
182
// These rules do not apply to untyped metrics.
170
183
t := mf .GetType ()
171
184
if t == dto .MetricType_UNTYPED {
@@ -206,7 +219,7 @@ func lintHistogramSummaryReserved(mf dto.MetricFamily) []Problem {
206
219
}
207
220
208
221
// 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 {
210
223
var problems []Problem
211
224
n := strings .ToLower (mf .GetName ())
212
225
@@ -224,7 +237,7 @@ func lintMetricTypeInName(mf dto.MetricFamily) []Problem {
224
237
}
225
238
226
239
// lintReservedChars detects colons in metric names.
227
- func lintReservedChars (mf dto.MetricFamily ) []Problem {
240
+ func lintReservedChars (mf * dto.MetricFamily ) []Problem {
228
241
var problems []Problem
229
242
if strings .Contains (mf .GetName (), ":" ) {
230
243
problems = append (problems , newProblem (mf , "metric names should not contain ':'" ))
@@ -235,7 +248,7 @@ func lintReservedChars(mf dto.MetricFamily) []Problem {
235
248
var camelCase = regexp .MustCompile (`[a-z][A-Z]` )
236
249
237
250
// lintCamelCase detects metric names and label names written in camelCase.
238
- func lintCamelCase (mf dto.MetricFamily ) []Problem {
251
+ func lintCamelCase (mf * dto.MetricFamily ) []Problem {
239
252
var problems []Problem
240
253
if camelCase .FindString (mf .GetName ()) != "" {
241
254
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 {
252
265
}
253
266
254
267
// lintUnitAbbreviations detects abbreviated units in the metric name.
255
- func lintUnitAbbreviations (mf dto.MetricFamily ) []Problem {
268
+ func lintUnitAbbreviations (mf * dto.MetricFamily ) []Problem {
256
269
var problems []Problem
257
270
n := strings .ToLower (mf .GetName ())
258
271
for _ , s := range unitAbbreviations {
0 commit comments