Skip to content

Commit 7c897f9

Browse files
committed
Add options to NewEncoder, start correcting its tests, reposition func description
Signed-off-by: Arianna Vespri <[email protected]>
1 parent 6b0e211 commit 7c897f9

File tree

3 files changed

+137
-77
lines changed

3 files changed

+137
-77
lines changed

expfmt/encode.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ func NegotiateIncludingOpenMetrics(h http.Header) Format {
116116
// for FmtOpenMetrics, but a future (breaking) release will add the Close method
117117
// to the Encoder interface directly. The current version of the Encoder
118118
// interface is kept for backwards compatibility.
119-
func NewEncoder(w io.Writer, format Format) Encoder {
119+
func NewEncoder(w io.Writer, format Format, options ...ToOpenMetricsOption) Encoder {
120120
switch format {
121121
case FmtProtoDelim:
122122
return encoderCloser{
@@ -153,7 +153,7 @@ func NewEncoder(w io.Writer, format Format) Encoder {
153153
case FmtOpenMetrics_0_0_1, FmtOpenMetrics_1_0_0:
154154
return encoderCloser{
155155
encode: func(v *dto.MetricFamily) error {
156-
_, err := MetricFamilyToOpenMetrics(w, v)
156+
_, err := MetricFamilyToOpenMetrics(w, v, options...)
157157
return err
158158
},
159159
close: func() error {

expfmt/encode_test.go

Lines changed: 117 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,7 @@ func TestNegotiateOpenMetrics(t *testing.T) {
104104
}
105105

106106
func TestEncode(t *testing.T) {
107-
var buff bytes.Buffer
108-
delimEncoder := NewEncoder(&buff, FmtProtoDelim)
109-
metric := &dto.MetricFamily{
107+
metric1 := &dto.MetricFamily{
110108
Name: proto.String("foo_metric"),
111109
Type: dto.MetricType_UNTYPED.Enum(),
112110
Metric: []*dto.Metric{
@@ -118,59 +116,122 @@ func TestEncode(t *testing.T) {
118116
},
119117
}
120118

121-
err := delimEncoder.Encode(metric)
122-
if err != nil {
123-
t.Errorf("unexpected error during encode: %s", err.Error())
124-
}
125-
126-
out := buff.Bytes()
127-
if len(out) == 0 {
128-
t.Errorf("expected the output bytes buffer to be non-empty")
129-
}
130-
131-
buff.Reset()
132-
133-
compactEncoder := NewEncoder(&buff, FmtProtoCompact)
134-
err = compactEncoder.Encode(metric)
135-
if err != nil {
136-
t.Errorf("unexpected error during encode: %s", err.Error())
137-
}
138-
139-
out = buff.Bytes()
140-
if len(out) == 0 {
141-
t.Errorf("expected the output bytes buffer to be non-empty")
142-
}
143-
144-
buff.Reset()
145-
146-
protoTextEncoder := NewEncoder(&buff, FmtProtoText)
147-
err = protoTextEncoder.Encode(metric)
148-
if err != nil {
149-
t.Errorf("unexpected error during encode: %s", err.Error())
150-
}
151-
152-
out = buff.Bytes()
153-
if len(out) == 0 {
154-
t.Errorf("expected the output bytes buffer to be non-empty")
155-
}
156-
157-
buff.Reset()
158-
159-
textEncoder := NewEncoder(&buff, FmtText)
160-
err = textEncoder.Encode(metric)
161-
if err != nil {
162-
t.Errorf("unexpected error during encode: %s", err.Error())
163-
}
164-
165-
out = buff.Bytes()
166-
if len(out) == 0 {
167-
t.Errorf("expected the output bytes buffer to be non-empty")
119+
scenarios := []struct {
120+
metric *dto.MetricFamily
121+
format Format
122+
withUnit bool
123+
out string
124+
}{
125+
// // 1: Untyped ProtoDelim
126+
// {
127+
// metric: metric1,
128+
// format: FmtProtoDelim,
129+
// out: ,
130+
// },
131+
// // 2: Untyped FmtProtoCompact
132+
// {
133+
// metric: metric1,
134+
// format: FmtProtoCompact,
135+
// out: ,
136+
// },
137+
// // 3: Untyped FmtProtoText
138+
// {
139+
// metric: metric1,
140+
// format: FmtProtoText,
141+
// out: ,
142+
// },
143+
// 4: Untyped FmtText
144+
{
145+
metric: metric1,
146+
format: FmtText,
147+
out: `# TYPE foo_metric untyped
148+
foo_metric 1.234
149+
`,
150+
},
151+
// 5: Untyped FmtOpenMetrics_0_0_1
152+
{
153+
metric: metric1,
154+
format: FmtOpenMetrics_0_0_1,
155+
out: `# TYPE foo_metric unknown
156+
foo_metric 1.234
157+
`,
158+
},
159+
// 6: Untyped FmtOpenMetrics_1_0_0
160+
{
161+
metric: metric1,
162+
format: FmtOpenMetrics_1_0_0,
163+
out: `# TYPE foo_metric unknown
164+
foo_metric 1.234
165+
`,
166+
},
167+
// 7: Simple Counter FmtOpenMetrics_0_0_1 unit opted in
168+
{
169+
metric: &dto.MetricFamily{
170+
Name: proto.String("foos_duration_seconds_total"),
171+
Help: proto.String("Duration of foos in seconds."),
172+
Type: dto.MetricType_COUNTER.Enum(),
173+
Unit: proto.String("seconds"),
174+
Metric: []*dto.Metric{
175+
{
176+
Counter: &dto.Counter{
177+
Value: proto.Float64(420),
178+
},
179+
},
180+
},
181+
},
182+
format: FmtOpenMetrics_0_0_1,
183+
withUnit: true,
184+
out: `# HELP foos_duration_seconds Duration of foos in seconds.
185+
# TYPE foos_duration_seconds counter
186+
# UNIT foos_duration_seconds seconds
187+
foos_duration_seconds_total 420.0
188+
`,
189+
},
190+
// 8: Simple Counter FmtOpenMetrics_1_0_0 unit opted out
191+
{
192+
metric: &dto.MetricFamily{
193+
Name: proto.String("foos_duration_seconds_total"),
194+
Help: proto.String("Duration of foos in seconds."),
195+
Type: dto.MetricType_COUNTER.Enum(),
196+
Metric: []*dto.Metric{
197+
{
198+
Counter: &dto.Counter{
199+
Value: proto.Float64(420),
200+
},
201+
},
202+
},
203+
},
204+
format: FmtOpenMetrics_1_0_0,
205+
out: `# HELP foos_duration_seconds Duration of foos in seconds.
206+
# TYPE foos_duration_seconds counter
207+
foos_duration_seconds_total 420.0
208+
`,
209+
},
168210
}
169-
170-
expected := "# TYPE foo_metric untyped\n" +
171-
"foo_metric 1.234\n"
172-
173-
if string(out) != expected {
174-
t.Errorf("expected TextEncoder to return %s, but got %s instead", expected, string(out))
211+
for i, scenario := range scenarios {
212+
opts := []ToOpenMetricsOption{}
213+
if scenario.withUnit {
214+
opts = append(opts, ToOpenMetricsWithUnit())
215+
}
216+
out := bytes.NewBuffer(make([]byte, 0, len(scenario.out)))
217+
enc := NewEncoder(out, scenario.format, opts...)
218+
err := enc.Encode(scenario.metric)
219+
if err != nil {
220+
t.Errorf("%d. error: %s", i, err)
221+
continue
222+
}
223+
224+
if expected, got := len(scenario.out), len(out.Bytes()); expected != got {
225+
t.Errorf(
226+
"%d. expected %d bytes written, got %d",
227+
i, expected, got,
228+
)
229+
}
230+
if expected, got := scenario.out, out.String(); expected != got {
231+
t.Errorf(
232+
"%d. expected out=%q, got %q",
233+
i, expected, got,
234+
)
235+
}
175236
}
176237
}

expfmt/openmetrics_create.go

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,24 @@ import (
2727
dto "github.com/prometheus/client_model/go"
2828
)
2929

30+
type ToOpenMetrics struct { // TODO: reunite the comment above with its right function!!
31+
withUnit bool
32+
// withCreated bool can be added in the future.
33+
}
34+
35+
type ToOpenMetricsOption = func(*ToOpenMetrics)
36+
37+
// ToOpenMetricsWithUnit is meant to be called as an optional argument in the MetricFamilyToOpenMetrics
38+
// function. It enables a set unit to be written to the output and to be added to the metric name, (if
39+
// it's not there already), as a suffix. Without opting in this way, the unit will not be added to the
40+
// metric name and, on top of that, the unit will not be passed onto the output, even if it were declared
41+
// in the *dto.MetricFamily struct, i.e. even if in.Unit !=nil.
42+
func ToOpenMetricsWithUnit() ToOpenMetricsOption {
43+
return func(om *ToOpenMetrics) {
44+
om.withUnit = true
45+
}
46+
}
47+
3048
// MetricFamilyToOpenMetrics converts a MetricFamily proto message into the
3149
// OpenMetrics text format and writes the resulting lines to 'out'. It returns
3250
// the number of bytes written and any error encountered. The output will have
@@ -69,25 +87,6 @@ import (
6987
//
7088
// - The value of Counters is not checked. (OpenMetrics doesn't allow counters
7189
// with a `NaN` value.)
72-
73-
type ToOpenMetrics struct {
74-
withUnit bool
75-
// withCreated bool can be added in the future.
76-
}
77-
78-
type ToOpenMetricsOption = func(*ToOpenMetrics)
79-
80-
// ToOpenMetricsWithUnit is meant to be called as an optional argument in the MetricFamilyToOpenMetrics
81-
// function. It enables a set unit to be written to the output and to be added to the metric name, (if
82-
// it's not there already), as a suffix. Without opting in this way, the unit will not be added to the
83-
// metric name and, on top of that, the unit will not be passed onto the output, even if it were declared
84-
// in the *dto.MetricFamily struct, i.e. even if in.Unit !=nil.
85-
func ToOpenMetricsWithUnit() ToOpenMetricsOption {
86-
return func(om *ToOpenMetrics) {
87-
om.withUnit = true
88-
}
89-
}
90-
9190
func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...ToOpenMetricsOption) (written int, err error) {
9291
toOM := ToOpenMetrics{}
9392
for _, option := range options {

0 commit comments

Comments
 (0)