Skip to content

Commit

Permalink
expfmt: Add a way to generate different OpenMetrics Formats
Browse files Browse the repository at this point in the history
Also complete test coverage of expfmt.go
  • Loading branch information
ywwg committed Mar 5, 2024
1 parent 36d0bf9 commit a75a825
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 6 deletions.
22 changes: 16 additions & 6 deletions expfmt/expfmt.go
Expand Up @@ -15,6 +15,7 @@
package expfmt

import (
"fmt"
"strings"

"github.com/prometheus/common/model"
Expand Down Expand Up @@ -63,7 +64,7 @@ const (
type FormatType int

const (
TypeUnknown = iota
TypeUnknown FormatType = iota
TypeProtoCompact
TypeProtoDelim
TypeProtoText
Expand All @@ -73,7 +74,8 @@ const (

// NewFormat generates a new Format from the type provided. Mostly used for
// tests, most Formats should be generated as part of content negotiation in
// encode.go.
// encode.go. If a type has more than one version, the latest version will be
// returned.
func NewFormat(t FormatType) Format {
switch t {
case TypeProtoCompact:
Expand All @@ -91,13 +93,21 @@ func NewFormat(t FormatType) Format {
}
}

// NewOpenMetricsFormat generates a new OpenMetrics format matching the
// specified version number.
func NewOpenMetricsFormat(version string) (Format, error) {
if version == OpenMetricsVersion_0_0_1 {
return fmtOpenMetrics_0_0_1, nil
}
if version == OpenMetricsVersion_1_0_0 {
return fmtOpenMetrics_1_0_0, nil
}
return fmtUnknown, fmt.Errorf("unknown open metrics version string")
}

// FormatType deduces an overall FormatType for the given format.
func (f Format) FormatType() FormatType {
toks := strings.Split(string(f), ";")
if len(toks) < 2 {
return TypeUnknown
}

params := make(map[string]string)
for i, t := range toks {
if i == 0 {
Expand Down
116 changes: 116 additions & 0 deletions expfmt/expfmt_test.go
@@ -0,0 +1,116 @@
package expfmt

import (
"testing"

"github.com/prometheus/common/model"
)

// Test Format to Escapting Scheme conversion
// Path: expfmt/expfmt_test.go
// Compare this snippet from expfmt/expfmt.go:
func TestToFormatType(t *testing.T) {
tests := []struct {
format Format
expected FormatType
}{
{
format: fmtProtoCompact,
expected: TypeProtoCompact,
},
{
format: fmtProtoDelim,
expected: TypeProtoDelim,
},
{
format: fmtProtoText,
expected: TypeProtoText,
},
{
format: fmtOpenMetrics_1_0_0,
expected: TypeOpenMetrics,
},
{
format: fmtText,
expected: TypeTextPlain,
},
{
format: fmtOpenMetrics_0_0_1,
expected: TypeOpenMetrics,
},
{
format: "application/vnd.google.protobuf; proto=BadProtocol; encoding=text",
expected: TypeUnknown,
},
{
format: "application/vnd.google.protobuf",
expected: TypeUnknown,
},
{
format: "application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily=bad",
expected: TypeUnknown,
},
// encoding missing
{
format: "application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily",
expected: TypeUnknown,
},
// invalid encoding
{
format: "application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=textual",
expected: TypeUnknown,
},
// bad charset, must be utf-8
{
format: "application/openmetrics-text; version=1.0.0; charset=ascii",
expected: TypeUnknown,
},
{
format: "text/plain",
expected: TypeTextPlain,
},
{
format: "text/plain; version=invalid",
expected: TypeUnknown,
},
{
format: "gobbledygook",
expected: TypeUnknown,
},
}
for _, test := range tests {
if test.format.FormatType() != test.expected {
t.Errorf("expected %v got %v", test.expected, test.format.FormatType())
}
}
}

func TestToEscapingScheme(t *testing.T) {
tests := []struct {
format Format
expected model.EscapingScheme
}{
{
format: fmtProtoCompact,
expected: model.ValueEncodingEscaping,
},
{
format: "application/openmetrics-text; version=1.0.0; charset=utf-8; escaping=underscores",
expected: model.UnderscoreEscaping,
},
{
format: "application/openmetrics-text; version=1.0.0; charset=utf-8; escaping=allow-utf-8",
expected: model.NoEscaping,
},
// error returns default
{
format: "application/openmetrics-text; version=1.0.0; charset=utf-8; escaping=invalid",
expected: model.NameEscapingScheme,
},
}
for _, test := range tests {
if test.format.ToEscapingScheme() != test.expected {
t.Errorf("expected %v got %v", test.expected, test.format.ToEscapingScheme())
}
}
}

0 comments on commit a75a825

Please sign in to comment.