Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 54 additions & 34 deletions prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ type MiddlewareConfig struct {
// metrics that need incremented/observed.
AfterNext func(c *echo.Context, err error)

// DisableRequestSizeMetric disables the `request_size_bytes` histogram. Each histogram adds a series per bucket
// for every label combination.
DisableRequestSizeMetric bool

// DisableResponseSizeMetric disables the `response_size_bytes` histogram.
DisableResponseSizeMetric bool

timeNow func() time.Time

// If DoNotUseRequestPathFor404 is true, all 404 responses (due to non-matching route) will have the same `url` label and
Expand Down Expand Up @@ -202,32 +209,38 @@ func (conf MiddlewareConfig) ToMiddleware() (echo.MiddlewareFunc, error) {
return nil, rErr
}

responseSize := prometheus.NewHistogramVec(
conf.HistogramOptsFunc(prometheus.HistogramOpts{
Namespace: conf.Namespace,
Subsystem: conf.Subsystem,
Name: "response_size_bytes",
Help: "The HTTP response sizes in bytes.",
Buckets: sizeBuckets,
}),
labelNames,
)
if err := conf.Registerer.Register(responseSize); err != nil {
return nil, err
var responseSize *prometheus.HistogramVec
if !conf.DisableResponseSizeMetric {
responseSize = prometheus.NewHistogramVec(
conf.HistogramOptsFunc(prometheus.HistogramOpts{
Namespace: conf.Namespace,
Subsystem: conf.Subsystem,
Name: "response_size_bytes",
Help: "The HTTP response sizes in bytes.",
Buckets: sizeBuckets,
}),
labelNames,
)
if err := conf.Registerer.Register(responseSize); err != nil {
return nil, err
}
}

requestSize := prometheus.NewHistogramVec(
conf.HistogramOptsFunc(prometheus.HistogramOpts{
Namespace: conf.Namespace,
Subsystem: conf.Subsystem,
Name: "request_size_bytes",
Help: "The HTTP request sizes in bytes.",
Buckets: sizeBuckets,
}),
labelNames,
)
if rErr := conf.Registerer.Register(requestSize); rErr != nil {
return nil, rErr
var requestSize *prometheus.HistogramVec
if !conf.DisableRequestSizeMetric {
requestSize = prometheus.NewHistogramVec(
conf.HistogramOptsFunc(prometheus.HistogramOpts{
Namespace: conf.Namespace,
Subsystem: conf.Subsystem,
Name: "request_size_bytes",
Help: "The HTTP request sizes in bytes.",
Buckets: sizeBuckets,
}),
labelNames,
)
if rErr := conf.Registerer.Register(requestSize); rErr != nil {
return nil, rErr
}
}

return func(next echo.HandlerFunc) echo.HandlerFunc {
Expand All @@ -241,7 +254,10 @@ func (conf MiddlewareConfig) ToMiddleware() (echo.MiddlewareFunc, error) {
if conf.BeforeNext != nil {
conf.BeforeNext(c)
}
reqSz := computeApproximateRequestSize(c.Request())
reqSz := 0
if requestSize != nil {
reqSz = computeApproximateRequestSize(c.Request())
}

start := conf.timeNow()
err := next(c)
Expand Down Expand Up @@ -277,17 +293,21 @@ func (conf MiddlewareConfig) ToMiddleware() (echo.MiddlewareFunc, error) {
} else {
return fmt.Errorf("failed to label request count metric with values, err: %w", err)
}
if obs, err := requestSize.GetMetricWithLabelValues(values...); err == nil {
obs.Observe(float64(reqSz))
} else {
return fmt.Errorf("failed to label request size metric with values, err: %w", err)
if requestSize != nil {
if obs, err := requestSize.GetMetricWithLabelValues(values...); err == nil {
obs.Observe(float64(reqSz))
} else {
return fmt.Errorf("failed to label request size metric with values, err: %w", err)
}
}
if obs, err := responseSize.GetMetricWithLabelValues(values...); err == nil {
if resp != nil {
obs.Observe(float64(resp.Size))
if responseSize != nil {
if obs, err := responseSize.GetMetricWithLabelValues(values...); err == nil {
if resp != nil {
obs.Observe(float64(resp.Size))
}
} else {
return fmt.Errorf("failed to label response size metric with values, err: %w", err)
}
} else {
return fmt.Errorf("failed to label response size metric with values, err: %w", err)
}

return err
Expand Down
20 changes: 20 additions & 0 deletions prometheus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,26 @@ func TestPrometheus_Buckets(t *testing.T) {
assert.NotContains(t, body, `echo_response_size_bytes_bucket{code="404",host="example.com",method="GET",url="/ping",le="0.005"}`, "response size should NOT have time bucket (like, 0.005s)")
}

func TestMiddlewareConfig_DisableSizeMetrics(t *testing.T) {
e := echo.New()

customRegistry := prometheus.NewRegistry()
e.Use(NewMiddlewareWithConfig(MiddlewareConfig{
Registerer: customRegistry,
DisableRequestSizeMetric: true,
DisableResponseSizeMetric: true,
}))
e.GET("/metrics", NewHandlerWithConfig(HandlerConfig{Gatherer: customRegistry}))

assert.Equal(t, http.StatusNotFound, request(e, "/ping"))

body, code := requestBody(e, "/metrics")
assert.Equal(t, http.StatusOK, code)
assert.Contains(t, body, `echo_request_duration_seconds_count{code="404",host="example.com",method="GET",url="/ping"} 1`)
assert.NotContains(t, body, `echo_request_size_bytes`)
assert.NotContains(t, body, `echo_response_size_bytes`)
}

func TestMiddlewareConfig_Skipper(t *testing.T) {
e := echo.New()

Expand Down