Skip to content

Commit d20fbfc

Browse files
timonegkSoumyaRaikwar
authored andcommitted
fix: fix logic for plain text fallback format
This pull requests fixes a logic error in metrics_writer.go where metrics headers are replaced when a protobuf format is requested. However, the existing logic is never used because the content type negotiation is already done in a previous step (in metrics_handler.go). There, the content type for proto-based formats is changed to text/plain before passing the argument to SanitizeHeaders. The pull request changes the condition in SanitizeHeaders to check for the plain-text format instead of protobuf. I changed the signature of SanitizeHeaders to accept expfmt.Format instead of string. This makes checking the content type a bit cleaner. If this is considered a breaking change, we can also change it to a string prefix comparison. I encountered the error when I tried to use native histogram parsing in prometheus and found errors while parsing kube-state-metrics' metrics. The issue is already described in #2587. Signed-off-by: Timon Engelke <[email protected]>
1 parent e565886 commit d20fbfc

File tree

3 files changed

+15
-14
lines changed

3 files changed

+15
-14
lines changed

pkg/metrics_store/metrics_writer.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func (m MetricsWriter) WriteAll(w io.Writer) error {
9292
}
9393

9494
// SanitizeHeaders sanitizes the headers of the given MetricsWriterList.
95-
func SanitizeHeaders(contentType string, writers MetricsWriterList) MetricsWriterList {
95+
func SanitizeHeaders(contentType expfmt.Format, writers MetricsWriterList) MetricsWriterList {
9696
var lastHeader string
9797
for _, writer := range writers {
9898
if len(writer.stores) > 0 {
@@ -104,8 +104,9 @@ func SanitizeHeaders(contentType string, writers MetricsWriterList) MetricsWrite
104104
// Skip this step if we encounter a repeated header, as it will be removed.
105105
if header != lastHeader && strings.HasPrefix(header, "# HELP") {
106106

107-
// If the requested content type was proto-based (such as FmtProtoDelim, FmtProtoText, or FmtProtoCompact), replace "info" and "statesets" with "gauge", as they are not recognized by Prometheus' protobuf machinery.
108-
if strings.HasPrefix(contentType, expfmt.ProtoType) {
107+
// If the requested content type is text/plain, replace "info" and "statesets" with "gauge", as they are not recognized by Prometheus' plain text machinery.
108+
// When Prometheus requests proto-based formats, this branch is also used because any requested format that is not OpenMetrics falls back to text/plain in metrics_handler.go
109+
if contentType.FormatType() == expfmt.TypeTextPlain {
109110
infoTypeString := string(metric.Info)
110111
stateSetTypeString := string(metric.StateSet)
111112
if strings.HasSuffix(header, infoTypeString) {

pkg/metrics_store/metrics_writer_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,8 @@ func TestSanitizeHeaders(t *testing.T) {
276276
expectedHeaders []string
277277
}{
278278
{
279-
name: "text-format unique headers",
280-
contentType: expfmt.NewFormat(expfmt.TypeTextPlain),
279+
name: "OpenMetricsText unique headers",
280+
contentType: expfmt.NewFormat(expfmt.TypeOpenMetrics),
281281
headers: []string{
282282
"",
283283
"# HELP foo foo_help\n# TYPE foo gauge",
@@ -293,8 +293,8 @@ func TestSanitizeHeaders(t *testing.T) {
293293
},
294294
},
295295
{
296-
name: "text-format consecutive duplicate headers",
297-
contentType: expfmt.NewFormat(expfmt.TypeTextPlain),
296+
name: "OpenMetricsText consecutive duplicate headers",
297+
contentType: expfmt.NewFormat(expfmt.TypeOpenMetrics),
298298
headers: []string{
299299
"",
300300
"",
@@ -316,8 +316,8 @@ func TestSanitizeHeaders(t *testing.T) {
316316
},
317317
},
318318
{
319-
name: "proto-format unique headers",
320-
contentType: expfmt.NewFormat(expfmt.TypeProtoText), // Prometheus ProtoFmt is the only proto-based format we check for.
319+
name: "text-format unique headers",
320+
contentType: expfmt.NewFormat(expfmt.TypeTextPlain),
321321
headers: []string{
322322
"",
323323
"# HELP foo foo_help\n# TYPE foo gauge",
@@ -331,8 +331,8 @@ func TestSanitizeHeaders(t *testing.T) {
331331
},
332332
},
333333
{
334-
name: "proto-format consecutive duplicate headers",
335-
contentType: expfmt.NewFormat(expfmt.TypeProtoText), // Prometheus ProtoFmt is the only proto-based format we check for.
334+
name: "text-format consecutive duplicate headers",
335+
contentType: expfmt.NewFormat(expfmt.TypeTextPlain),
336336
headers: []string{
337337
"",
338338
"",
@@ -356,7 +356,7 @@ func TestSanitizeHeaders(t *testing.T) {
356356
for _, testcase := range testcases {
357357
writer := NewMetricsWriter(NewMetricsStore(testcase.headers, nil))
358358
t.Run(testcase.name, func(t *testing.T) {
359-
SanitizeHeaders(string(testcase.contentType), MetricsWriterList{writer})
359+
SanitizeHeaders(testcase.contentType, MetricsWriterList{writer})
360360
if !reflect.DeepEqual(testcase.expectedHeaders, writer.stores[0].headers) {
361361
t.Fatalf("(-want, +got):\n%s", cmp.Diff(testcase.expectedHeaders, writer.stores[0].headers))
362362
}
@@ -404,7 +404,7 @@ func BenchmarkSanitizeHeaders(b *testing.B) {
404404
writer := NewMetricsWriter(NewMetricsStore(headers, nil))
405405
b.Run(benchmark.name, func(b *testing.B) {
406406
for i := 0; i < b.N; i++ {
407-
SanitizeHeaders(string(benchmark.contentType), MetricsWriterList{writer})
407+
SanitizeHeaders(benchmark.contentType, MetricsWriterList{writer})
408408
}
409409
})
410410
}

pkg/metricshandler/metrics_handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ func (m *MetricsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
220220
}
221221
}
222222

223-
m.metricsWriters = metricsstore.SanitizeHeaders(string(contentType), m.metricsWriters)
223+
m.metricsWriters = metricsstore.SanitizeHeaders(contentType, m.metricsWriters)
224224
for _, w := range m.metricsWriters {
225225
err := w.WriteAll(writer)
226226
if err != nil {

0 commit comments

Comments
 (0)