Skip to content
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

feature: add ResponseFormatIncludingMetrics helper func #503

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 42 additions & 0 deletions expfmt/decode.go
Expand Up @@ -69,6 +69,48 @@ func ResponseFormat(h http.Header) Format {
return FmtUnknown
}

// ResponseFormatIncludingOpenMetrics works like ResponseFormat but includes
// FmtOpenMetrics as an option for the result. Note that this function is
// temporary and will disappear once FmtOpenMetrics is fully supported and as
// such may be returned by the normal ResponseFormat function.
func ResponseFormatIncludingOpenMetrics(h http.Header) Format {
ct := h.Get(hdrContentType)

mediatype, params, err := mime.ParseMediaType(ct)
if err != nil {
return FmtUnknown
}

const textType = "text/plain"

switch mediatype {
case ProtoType:
if p, ok := params["proto"]; ok && p != ProtoProtocol {
return FmtUnknown
}
if e, ok := params["encoding"]; ok && e != "delimited" {
return FmtUnknown
}
return FmtProtoDelim

case textType:
if v, ok := params["version"]; ok && v != TextVersion {
return FmtUnknown
}
return FmtText

case OpenMetricsType:
switch params["version"] {
case OpenMetricsVersion_1_0_0:
return FmtOpenMetrics_1_0_0
case OpenMetricsVersion_0_0_1, "":
return FmtOpenMetrics_0_0_1
}
}

return FmtUnknown
}

// NewDecoder returns a new decoder based on the given input format.
// If the input format does not imply otherwise, a text format decoder is returned.
func NewDecoder(r io.Reader, format Format) Decoder {
Expand Down
74 changes: 74 additions & 0 deletions expfmt/decode_test.go
Expand Up @@ -418,16 +418,90 @@ func testDiscriminatorHTTPHeader(t testing.TB) {
}
}

func testDiscriminatorHTTPHeaderOpenMetrics(t testing.TB) {
var scenarios = []struct {
input map[string]string
output Format
}{
// OpenMetrics
{
input: map[string]string{"Content-Type": `application/openmetrics-text`},
output: FmtOpenMetrics_0_0_1,
},
{
input: map[string]string{"Content-Type": `application/openmetrics-text;version=0.0.1`},
output: FmtOpenMetrics_0_0_1,
},
{
input: map[string]string{"Content-Type": `application/openmetrics-text;version=1.0.0`},
output: FmtOpenMetrics_1_0_0,
},
// Other
{
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="delimited"`},
output: FmtProtoDelim,
},
{
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="illegal"; encoding="delimited"`},
output: FmtUnknown,
},
{
input: map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="illegal"`},
output: FmtUnknown,
},
{
input: map[string]string{"Content-Type": `text/plain; version=0.0.4`},
output: FmtText,
},
{
input: map[string]string{"Content-Type": `text/plain`},
output: FmtText,
},
{
input: map[string]string{"Content-Type": `text/plain; version=0.0.3`},
output: FmtUnknown,
},
}

for i, scenario := range scenarios {
var header http.Header

if len(scenario.input) > 0 {
header = http.Header{}
}

for key, value := range scenario.input {
header.Add(key, value)
}

actual := ResponseFormatIncludingOpenMetrics(header)

if scenario.output != actual {
t.Errorf("%d. expected %s, got %s", i, scenario.output, actual)
}
}
}

func TestDiscriminatorHTTPHeader(t *testing.T) {
testDiscriminatorHTTPHeader(t)
}

func TestDiscriminatorHTTPHeaderOpenMetrics(t *testing.T) {
testDiscriminatorHTTPHeaderOpenMetrics(t)
}

func BenchmarkDiscriminatorHTTPHeader(b *testing.B) {
for i := 0; i < b.N; i++ {
testDiscriminatorHTTPHeader(b)
}
}

func BenchmarkDiscriminatorHTTPHeaderOpenMetrics(b *testing.B) {
for i := 0; i < b.N; i++ {
testDiscriminatorHTTPHeaderOpenMetrics(b)
}
}

func TestExtractSamples(t *testing.T) {
var (
goodMetricFamily1 = &dto.MetricFamily{
Expand Down