diff --git a/app/kuma-dp/pkg/dataplane/metrics/consts.go b/app/kuma-dp/pkg/dataplane/metrics/consts.go new file mode 100644 index 000000000000..1b920542374f --- /dev/null +++ b/app/kuma-dp/pkg/dataplane/metrics/consts.go @@ -0,0 +1,12 @@ +package metrics + +import ( + "strings" + + "github.com/prometheus/common/expfmt" +) + +var FmtOpenMetrics_1_0_0 = expfmt.NewFormat(expfmt.TypeOpenMetrics) + +// for some reason 0.0.1 is not taken into account in expfmt.NewFormat +var FmtOpenMetrics_0_0_1 = expfmt.Format(strings.ReplaceAll(string(FmtOpenMetrics_1_0_0), expfmt.OpenMetricsVersion_1_0_0, expfmt.OpenMetricsVersion_0_0_1)) diff --git a/app/kuma-dp/pkg/dataplane/metrics/server.go b/app/kuma-dp/pkg/dataplane/metrics/server.go index fd272a75ec57..ec28d15e1bea 100644 --- a/app/kuma-dp/pkg/dataplane/metrics/server.go +++ b/app/kuma-dp/pkg/dataplane/metrics/server.go @@ -41,10 +41,10 @@ var ( // holds prometheus content types in order of priority. prometheusPriorityContentType = []expfmt.Format{ - expfmt.FmtOpenMetrics_1_0_0, - expfmt.FmtOpenMetrics_0_0_1, - expfmt.FmtText, - expfmt.FmtUnknown, + FmtOpenMetrics_1_0_0, + FmtOpenMetrics_0_0_1, + expfmt.NewFormat(expfmt.TypeTextPlain), + expfmt.NewFormat(expfmt.TypeUnknown), } // Reverse mapping of prometheusPriorityContentType for faster lookup. @@ -274,7 +274,7 @@ func processMetrics(contents <-chan []byte, contentType expfmt.Format) []byte { buf.Reset() buf.Write(processedMetrics) - if contentType == expfmt.FmtOpenMetrics_1_0_0 || contentType == expfmt.FmtOpenMetrics_0_0_1 { + if contentType == FmtOpenMetrics_1_0_0 || contentType == FmtOpenMetrics_0_0_1 { // make metrics OpenMetrics compliant buf.Write([]byte("# EOF\n")) } @@ -321,7 +321,7 @@ func selectContentType(contentTypes <-chan expfmt.Format, reqHeader http.Header) // So it's better to choose the highest negotiated content type between the // target apps and the scraper. var ctPriority int32 = math.MaxInt32 - ct := expfmt.FmtUnknown + ct := expfmt.NewFormat(expfmt.TypeUnknown) for contentType := range contentTypes { priority, valid := prometheusPriorityContentTypeLookup[contentType] if !valid { @@ -335,7 +335,7 @@ func selectContentType(contentTypes <-chan expfmt.Format, reqHeader http.Header) // If no valid content type is returned by the target applications, // negotitate content type based on Accept header of the scraper. - if ct == expfmt.FmtUnknown { + if ct == expfmt.NewFormat(expfmt.TypeUnknown) { ct = expfmt.Negotiate(reqHeader) } @@ -415,7 +415,7 @@ func responseFormat(h http.Header) expfmt.Format { mediatype, params, err := mime.ParseMediaType(ct) if err != nil { - return expfmt.FmtUnknown + return expfmt.NewFormat(expfmt.TypeUnknown) } version := params["version"] @@ -426,25 +426,25 @@ func responseFormat(h http.Header) expfmt.Format { e := params["encoding"] // only delimited encoding is supported by prometheus scraper if p == expfmt.ProtoProtocol && e == "delimited" { - return expfmt.FmtProtoDelim + return expfmt.NewFormat(expfmt.TypeProtoDelim) } // if mediatype is `text/plain`, return Prometheus text format // without checking the version, as there are few exporters // which don't set the version param in the content-type header. ex: Envoy case textType: - return expfmt.FmtText + return expfmt.NewFormat(expfmt.TypeTextPlain) - // if mediatype is OpenMetricsType, return FmtUnknown for any version + // if mediatype is OpenMetricsType, return expfmt.NewFormat(expfmt.TypeUnknown) for any version // other than "0.0.1", "1.0.0" and "". case expfmt.OpenMetricsType: if version == expfmt.OpenMetricsVersion_0_0_1 || version == "" { - return expfmt.FmtOpenMetrics_0_0_1 + return FmtOpenMetrics_0_0_1 } if version == expfmt.OpenMetricsVersion_1_0_0 { - return expfmt.FmtOpenMetrics_1_0_0 + return FmtOpenMetrics_1_0_0 } } - return expfmt.FmtUnknown + return expfmt.NewFormat(expfmt.TypeUnknown) } diff --git a/app/kuma-dp/pkg/dataplane/metrics/server_test.go b/app/kuma-dp/pkg/dataplane/metrics/server_test.go index 4dab92c1a690..bc71c2eb0d94 100644 --- a/app/kuma-dp/pkg/dataplane/metrics/server_test.go +++ b/app/kuma-dp/pkg/dataplane/metrics/server_test.go @@ -82,14 +82,14 @@ var _ = Describe("Select Content Type", func() { It("should honor app content-type", func() { contentTypes := make(chan expfmt.Format, 3) - contentTypes <- expfmt.FmtOpenMetrics_0_0_1 + contentTypes <- FmtOpenMetrics_0_0_1 contentTypes <- expfmt.Format("") - contentTypes <- expfmt.FmtText + contentTypes <- expfmt.NewFormat(expfmt.TypeTextPlain) close(contentTypes) reqHeader.Add("Accept", "application/openmetrics-text;version=1.0.0,application/openmetrics-text;version=0.0.1;q=0.75,text/plain;version=0.0.4;q=0.5,*/*;q=0.1") actualContentType := selectContentType(contentTypes, reqHeader) - Expect(actualContentType).To(Equal(expfmt.FmtOpenMetrics_0_0_1)) + Expect(actualContentType).To(Equal(FmtOpenMetrics_0_0_1)) }) It("should negotiate content-type based on Accept header", func() { @@ -126,35 +126,35 @@ var _ = Describe("Response Format", func() { }, Entry("return FmtProtoDelim for a 'delimited protobuf content type' response", testCase{ contentType: "application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited", - expectedFormat: expfmt.FmtProtoDelim, + expectedFormat: expfmt.NewFormat(expfmt.TypeProtoDelim), }), - Entry("return FmtUnknown for a 'text protobuf content type' response", testCase{ + Entry("return expfmt.NewFormat(expfmt.TypeUnknown) for a 'text protobuf content type' response", testCase{ contentType: "application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=text", - expectedFormat: expfmt.FmtUnknown, + expectedFormat: expfmt.NewFormat(expfmt.TypeUnknown), }), Entry("return FmtText for a 'text plain content type' response", testCase{ contentType: "text/plain; charset=UTF-8", - expectedFormat: expfmt.FmtText, + expectedFormat: expfmt.NewFormat(expfmt.TypeTextPlain), }), Entry("return FmtOpenMetrics_1_0_0 for a 'openmetrics v1.0.0 content type' response", testCase{ contentType: "application/openmetrics-text; version=1.0.0", - expectedFormat: expfmt.FmtOpenMetrics_1_0_0, + expectedFormat: FmtOpenMetrics_1_0_0, }), Entry("return FmtOpenMetrics_0_0_1 for a 'openmetrics v0.0.1 content type' response", testCase{ contentType: "application/openmetrics-text; version=0.0.1", - expectedFormat: expfmt.FmtOpenMetrics_0_0_1, + expectedFormat: FmtOpenMetrics_0_0_1, }), - Entry("return FmtUnknown for a 'invalid content type' response", testCase{ + Entry("return expfmt.NewFormat(expfmt.TypeUnknown) for a 'invalid content type' response", testCase{ contentType: "application/invalid", - expectedFormat: expfmt.FmtUnknown, + expectedFormat: expfmt.NewFormat(expfmt.TypeUnknown), }), Entry("return FmtOpenMetrics_0_0_1 for a 'openmetrics content type with no version param' response", testCase{ contentType: "application/openmetrics-text", - expectedFormat: expfmt.FmtOpenMetrics_0_0_1, + expectedFormat: FmtOpenMetrics_0_0_1, }), - Entry("return FmtUnknown for a 'openmetrics content type with unsupported version param' response", testCase{ + Entry("return expfmt.NewFormat(expfmt.TypeUnknown) for a 'openmetrics content type with unsupported version param' response", testCase{ contentType: "application/openmetrics-text; version=2.0.0", - expectedFormat: expfmt.FmtUnknown, + expectedFormat: expfmt.NewFormat(expfmt.TypeUnknown), }), ) }) @@ -187,17 +187,17 @@ var _ = Describe("Process Metrics", func() { }, Entry("return OpenMetrics compliant metrics", testCase{ input: []string{"openmetrics_0_1_1.in", "counter.out"}, - contentType: expfmt.FmtOpenMetrics_0_0_1, + contentType: FmtOpenMetrics_0_0_1, expected: "openmetrics_0_0_1-counter.out", }), Entry("handle multiple # EOF", testCase{ input: []string{"openmetrics_0_1_1.in", "openmetrics_0_1_1.in", "counter.out"}, - contentType: expfmt.FmtOpenMetrics_0_0_1, + contentType: FmtOpenMetrics_0_0_1, expected: "multi-openmetrics-counter.out", }), Entry("return Prometheus text compliant metrics", testCase{ input: []string{"prom-text.in", "counter.out"}, - contentType: expfmt.FmtText, + contentType: expfmt.NewFormat(expfmt.TypeTextPlain), expected: "prom-text-counter.out", }), ) diff --git a/go.mod b/go.mod index 834deb8483d2..a8e36c0cc603 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.18.0 github.com/prometheus/client_model v0.6.0 - github.com/prometheus/common v0.47.0 + github.com/prometheus/common v0.48.0 github.com/sethvargo/go-retry v0.2.4 github.com/shopspring/decimal v1.3.1 github.com/slok/go-http-metrics v0.11.0 diff --git a/go.sum b/go.sum index 97bb7be2f817..a1a534698e86 100644 --- a/go.sum +++ b/go.sum @@ -393,8 +393,8 @@ github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlk github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= -github.com/prometheus/common v0.47.0 h1:p5Cz0FNHo7SnWOmWmoRozVcjEp0bIVU8cV7OShpjL1k= -github.com/prometheus/common v0.47.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= diff --git a/test/e2e_env/universal/observability/applications_metrics.go b/test/e2e_env/universal/observability/applications_metrics.go index bab785fa707d..f41192c1a0f1 100644 --- a/test/e2e_env/universal/observability/applications_metrics.go +++ b/test/e2e_env/universal/observability/applications_metrics.go @@ -213,7 +213,7 @@ metrics: // then g.Expect(err).ToNot(HaveOccurred()) g.Expect(stdout).ToNot(BeNil()) - g.Expect(stdout).To(ContainSubstring(string(expfmt.FmtText))) + g.Expect(stdout).To(ContainSubstring(string(expfmt.NewFormat(expfmt.TypeTextPlain)))) // response doesn't exist because was disabled g.Expect(stdout).ToNot(ContainSubstring("path-stats")) @@ -244,7 +244,7 @@ metrics: // then g.Expect(err).ToNot(HaveOccurred()) g.Expect(stdout).ToNot(BeNil()) - g.Expect(stdout).To(ContainSubstring(string(expfmt.FmtText))) + g.Expect(stdout).To(ContainSubstring(string(expfmt.NewFormat(expfmt.TypeTextPlain)))) // path doesn't have defined address g.Expect(stdout).ToNot(ContainSubstring("localhost-bound-not-exposed"))