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

Add proper buckets for request/response sizes. #73

Merged
merged 2 commits into from
Apr 5, 2022
Merged
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
30 changes: 27 additions & 3 deletions prometheus/prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,24 @@ import (
var defaultMetricPath = "/metrics"
var defaultSubsystem = "echo"

const (
_ = iota // ignore first value by assigning to blank identifier
KB float64 = 1 << (10 * iota)
MB
GB
TB
)

// reqDurBuckets is the buckets for request duration. Here, we use the prometheus defaults
// which are for ~10s request length max: []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10}
var reqDurBuckets = prometheus.DefBuckets

// reqSzBuckets is the buckets for request size. Here we define a spectrom from 1KB thru 1NB up to 10MB.
var reqSzBuckets = []float64{1.0 * KB, 2.0 * KB, 5.0 * KB, 10.0 * KB, 100 * KB, 500 * KB, 1.0 * MB, 2.5 * MB, 5.0 * MB, 10.0 * MB}

// resSzBuckets is the buckets for response size. Here we define a spectrom from 1KB thru 1NB up to 10MB.
var resSzBuckets = []float64{1.0 * KB, 2.0 * KB, 5.0 * KB, 10.0 * KB, 100 * KB, 500 * KB, 1.0 * MB, 2.5 * MB, 5.0 * MB, 10.0 * MB}

// Standard default metrics
// counter, counter_vec, gauge, gauge_vec,
// histogram, histogram_vec, summary, summary_vec
Expand All @@ -54,21 +72,24 @@ var reqDur = &Metric{
Name: "request_duration_seconds",
Description: "The HTTP request latencies in seconds.",
Args: []string{"code", "method", "url"},
Type: "histogram_vec"}
Type: "histogram_vec",
Buckets: reqDurBuckets}

var resSz = &Metric{
ID: "resSz",
Name: "response_size_bytes",
Description: "The HTTP response sizes in bytes.",
Args: []string{"code", "method", "url"},
Type: "histogram_vec"}
Type: "histogram_vec",
Buckets: resSzBuckets}

var reqSz = &Metric{
ID: "reqSz",
Name: "request_size_bytes",
Description: "The HTTP request sizes in bytes.",
Args: []string{"code", "method", "url"},
Type: "histogram_vec"}
Type: "histogram_vec",
Buckets: reqSzBuckets}

var standardMetrics = []*Metric{
reqCnt,
Expand Down Expand Up @@ -108,6 +129,7 @@ type Metric struct {
Description string
Type string
Args []string
Buckets []float64
}

// Prometheus contains the metrics gathered by the instance and its path
Expand Down Expand Up @@ -307,6 +329,7 @@ func NewMetric(m *Metric, subsystem string) prometheus.Collector {
Subsystem: subsystem,
Name: m.Name,
Help: m.Description,
Buckets: m.Buckets,
},
m.Args,
)
Expand All @@ -316,6 +339,7 @@ func NewMetric(m *Metric, subsystem string) prometheus.Collector {
Subsystem: subsystem,
Name: m.Name,
Help: m.Description,
Buckets: m.Buckets,
},
)
case "summary_vec":
Expand Down
24 changes: 24 additions & 0 deletions prometheus/prometheus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,30 @@ func TestPrometheus_Use(t *testing.T) {
unregister(p)
}

func TestPrometheus_Buckets(t *testing.T) {
e := echo.New()
p := NewPrometheus("echo", nil)
p.Use(e)

path := "/ping"

g := gofight.New()
g.GET(path).Run(e, func(r gofight.HTTPResponse, rq gofight.HTTPRequest) { assert.Equal(t, http.StatusNotFound, r.Code) })

g.GET(p.MetricsPath).Run(e, func(r gofight.HTTPResponse, rq gofight.HTTPRequest) {
assert.Equal(t, http.StatusOK, r.Code)
assert.Contains(t, r.Body.String(), fmt.Sprintf("%s_request_duration_seconds", p.Subsystem))
assert.Regexp(t, "request_duration_seconds.*le=\"0.005\"", r.Body.String(), "duration should have time bucket (like, 0.005s)")
assert.NotRegexp(t, "request_duration_seconds.*le=\"512000\"", r.Body.String(), "duration should NOT have a size bucket (like, 512K)")
assert.Regexp(t, "response_size_bytes.*le=\"512000\"", r.Body.String(), "response size should have a 512K (size) bucket")
assert.NotRegexp(t, "response_size_bytes.*le=\"0.005\"", r.Body.String(), "response size should NOT have time bucket (like, 0.005s)")
assert.Regexp(t, "request_size_bytes.*le=\"512000\"", r.Body.String(), "request size should have a 512K (size) bucket")
assert.NotRegexp(t, "request_size_bytes.*le=\"0.005\"", r.Body.String(), "request should NOT have time bucket (like, 0.005s)")
})

unregister(p)
}

func TestPath(t *testing.T) {
p := NewPrometheus("echo", nil)
assert.Equal(t, p.MetricsPath, defaultMetricPath, "no usage of path should yield default path")
Expand Down