Skip to content

Commit 132ccde

Browse files
authored
Create new cortex_querier_codec_response_size histogram to track the size of the encoded Query responses (#6444)
* Create new histogram to track the size of the encoded responses from QF to Querier Signed-off-by: alanprot <[email protected]> * Changelog Signed-off-by: alanprot <[email protected]> --------- Signed-off-by: alanprot <[email protected]>
1 parent ddc77ee commit 132ccde

File tree

4 files changed

+87
-4
lines changed

4 files changed

+87
-4
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
* [ENHANCEMENT] Ingester: Make sure unregistered ingester joining the ring after WAL replay. #6277
5151
* [ENHANCEMENT] Distributor: Add a new `-distributor.num-push-workers` flag to use a goroutine worker pool when sending data from distributor to ingesters. #6406
5252
* [ENHANCEMENT] Ingester: If a limit per label set entry doesn't have any label, use it as the default partition to catch all series that doesn't match any other label sets entries. #6435
53+
* [ENHANCEMENT] Querier: Add new `cortex_querier_codec_response_size` metric to track the size of the encoded query responses from queriers. #6444
5354
* [BUGFIX] Runtime-config: Handle absolute file paths when working directory is not / #6224
5455
* [BUGFIX] Ruler: Allow rule evaluation to complete during shutdown. #6326
5556
* [BUGFIX] Ring: update ring with new ip address when instance is lost, rejoins, but heartbeat is disabled. #6271

pkg/api/handlers.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -231,11 +231,15 @@ func NewQuerierHandler(
231231
nil,
232232
false,
233233
)
234+
// Let's clear all codecs to create the instrumented ones
235+
api.ClearCodecs()
236+
cm := codec.NewInstrumentedCodecMetrics(reg)
234237

235-
// JSON codec is already installed. Install Protobuf codec to give the option for using either.
236-
api.InstallCodec(codec.ProtobufCodec{CortexInternal: false})
238+
api.InstallCodec(codec.NewInstrumentedCodec(v1.JSONCodec{}, cm))
239+
// Install Protobuf codec to give the option for using either.
240+
api.InstallCodec(codec.NewInstrumentedCodec(codec.ProtobufCodec{CortexInternal: false}, cm))
237241
// Protobuf codec for Cortex internal requests. This should be used by Cortex Ruler only for remote evaluation.
238-
api.InstallCodec(codec.ProtobufCodec{CortexInternal: true})
242+
api.InstallCodec(codec.NewInstrumentedCodec(codec.ProtobufCodec{CortexInternal: true}, cm))
239243

240244
router := mux.NewRouter()
241245

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package codec
2+
3+
import (
4+
"time"
5+
6+
"github.com/prometheus/client_golang/prometheus"
7+
"github.com/prometheus/client_golang/prometheus/promauto"
8+
v1 "github.com/prometheus/prometheus/web/api/v1"
9+
"github.com/weaveworks/common/middleware"
10+
)
11+
12+
type InstrumentedCodecMetrics struct {
13+
responseSizeHistogram *prometheus.HistogramVec
14+
}
15+
16+
func NewInstrumentedCodecMetrics(reg prometheus.Registerer) *InstrumentedCodecMetrics {
17+
return &InstrumentedCodecMetrics{
18+
responseSizeHistogram: promauto.With(reg).NewHistogramVec(prometheus.HistogramOpts{
19+
Namespace: "cortex",
20+
Name: "querier_codec_response_size",
21+
Help: "Size of the encoded prometheus response from the queriers.",
22+
Buckets: middleware.BodySizeBuckets,
23+
NativeHistogramBucketFactor: 1.1,
24+
NativeHistogramMaxBucketNumber: 100,
25+
NativeHistogramMinResetDuration: time.Hour,
26+
}, []string{"content_type"}),
27+
}
28+
}
29+
30+
type InstrumentedCodec struct {
31+
uc v1.Codec
32+
33+
metrics *InstrumentedCodecMetrics
34+
}
35+
36+
func (c *InstrumentedCodec) ContentType() v1.MIMEType {
37+
return c.uc.ContentType()
38+
}
39+
40+
func (c *InstrumentedCodec) CanEncode(resp *v1.Response) bool {
41+
return c.uc.CanEncode(resp)
42+
}
43+
44+
func (c *InstrumentedCodec) Encode(resp *v1.Response) ([]byte, error) {
45+
b, err := c.uc.Encode(resp)
46+
if err == nil {
47+
c.metrics.responseSizeHistogram.WithLabelValues(c.uc.ContentType().String()).Observe(float64(len((b))))
48+
}
49+
return b, err
50+
}
51+
52+
func NewInstrumentedCodec(uc v1.Codec, m *InstrumentedCodecMetrics) v1.Codec {
53+
return &InstrumentedCodec{
54+
uc: uc,
55+
metrics: m,
56+
}
57+
}

pkg/querier/codec/protobuf_codec_test.go

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package codec
22

33
import (
4+
"bytes"
5+
"fmt"
46
"testing"
57

68
"github.com/gogo/protobuf/proto"
9+
"github.com/prometheus/client_golang/prometheus"
10+
"github.com/prometheus/client_golang/prometheus/testutil"
711
"github.com/prometheus/common/model"
812
"github.com/prometheus/prometheus/model/histogram"
913
"github.com/prometheus/prometheus/model/labels"
@@ -437,7 +441,9 @@ func TestProtobufCodec_Encode(t *testing.T) {
437441

438442
for _, test := range tests {
439443
t.Run(test.name, func(t *testing.T) {
440-
codec := ProtobufCodec{CortexInternal: test.cortexInternal}
444+
reg := prometheus.NewPedanticRegistry()
445+
cm := NewInstrumentedCodecMetrics(reg)
446+
codec := NewInstrumentedCodec(ProtobufCodec{CortexInternal: test.cortexInternal}, cm)
441447
body, err := codec.Encode(&v1.Response{
442448
Status: tripperware.StatusSuccess,
443449
Data: test.data,
@@ -446,6 +452,21 @@ func TestProtobufCodec_Encode(t *testing.T) {
446452
b, err := proto.Marshal(test.expected)
447453
require.NoError(t, err)
448454
require.Equal(t, string(b), string(body))
455+
require.NoError(t, testutil.GatherAndCompare(reg, bytes.NewBufferString(fmt.Sprintf(`
456+
# HELP cortex_querier_codec_response_size Size of the encoded prometheus response from the queriers.
457+
# TYPE cortex_querier_codec_response_size histogram
458+
cortex_querier_codec_response_size_bucket{content_type="`+codec.ContentType().String()+`",le="1.048576e+06"} 1
459+
cortex_querier_codec_response_size_bucket{content_type="`+codec.ContentType().String()+`",le="2.62144e+06"} 1
460+
cortex_querier_codec_response_size_bucket{content_type="`+codec.ContentType().String()+`",le="5.24288e+06"} 1
461+
cortex_querier_codec_response_size_bucket{content_type="`+codec.ContentType().String()+`",le="1.048576e+07"} 1
462+
cortex_querier_codec_response_size_bucket{content_type="`+codec.ContentType().String()+`",le="2.62144e+07"} 1
463+
cortex_querier_codec_response_size_bucket{content_type="`+codec.ContentType().String()+`",le="5.24288e+07"} 1
464+
cortex_querier_codec_response_size_bucket{content_type="`+codec.ContentType().String()+`",le="1.048576e+08"} 1
465+
cortex_querier_codec_response_size_bucket{content_type="`+codec.ContentType().String()+`",le="2.62144e+08"} 1
466+
cortex_querier_codec_response_size_bucket{content_type="`+codec.ContentType().String()+`",le="+Inf"} 1
467+
cortex_querier_codec_response_size_sum{content_type="`+codec.ContentType().String()+`"} %v
468+
cortex_querier_codec_response_size_count{content_type="`+codec.ContentType().String()+`"} 1
469+
`, len(body))), "cortex_querier_codec_response_size"))
449470
})
450471
}
451472
}

0 commit comments

Comments
 (0)