Merge pull request #302 from prometheus/beorn7/http

Improve promhttp middleware
This commit is contained in:
Björn Rabenstein 2017-05-11 16:12:51 +02:00 committed by GitHub
commit 42552c195d
3 changed files with 56 additions and 43 deletions

View File

@ -28,6 +28,8 @@ func TestClientMiddlewareAPI(t *testing.T) {
client := http.DefaultClient
client.Timeout = 1 * time.Second
reg := prometheus.NewRegistry()
inFlightGauge := prometheus.NewGauge(prometheus.GaugeOpts{
Name: "client_in_flight_requests",
Help: "A gauge of in-flight requests for the wrapped client.",
@ -68,7 +70,7 @@ func TestClientMiddlewareAPI(t *testing.T) {
[]string{"method"},
)
prometheus.MustRegister(counter, tlsLatencyVec, dnsLatencyVec, histVec, inFlightGauge)
reg.MustRegister(counter, tlsLatencyVec, dnsLatencyVec, histVec, inFlightGauge)
trace := &InstrumentTrace{
DNSStart: func(t float64) {

View File

@ -27,6 +27,9 @@ import (
"github.com/prometheus/client_golang/prometheus"
)
// magicString is used for the hacky label test in checkLabels. Remove once fixed.
const magicString = "zZgWfBxLqvG8kc8IMv3POi2Bb0tZI3vAnBx+gBaFi9FyPzB/CzKUer1yufDa"
// InstrumentHandlerInFlight is a middleware that wraps the provided
// http.Handler. It sets the provided prometheus.Gauge to the number of
// requests currently handled by the wrapped http.Handler.
@ -191,37 +194,46 @@ func checkLabels(c prometheus.Collector) (code bool, method bool) {
if _, err := prometheus.NewConstMetric(desc, prometheus.UntypedValue, 0); err == nil {
return
} else if m, err := prometheus.NewConstMetric(desc, prometheus.UntypedValue, 0, ""); err == nil {
}
if m, err := prometheus.NewConstMetric(desc, prometheus.UntypedValue, 0, magicString); err == nil {
if err := m.Write(&pm); err != nil {
panic("error checking metric for labels")
}
name := *pm.Label[0].Name
if name == "code" {
code = true
} else if name == "method" {
method = true
} else {
panic("metric partitioned with non-supported labels")
}
return
} else if m, err := prometheus.NewConstMetric(desc, prometheus.UntypedValue, 0, "", ""); err == nil {
if err := m.Write(&pm); err != nil {
panic("error checking metric for labels")
}
for _, label := range pm.Label {
if *label.Name == "code" || *label.Name == "method" {
name, value := label.GetName(), label.GetValue()
if value != magicString {
continue
}
switch name {
case "code":
code = true
case "method":
method = true
default:
panic("metric partitioned with non-supported labels")
}
return
}
panic("previously set label not found this must never happen")
}
if m, err := prometheus.NewConstMetric(desc, prometheus.UntypedValue, 0, magicString, magicString); err == nil {
if err := m.Write(&pm); err != nil {
panic("error checking metric for labels")
}
for _, label := range pm.Label {
name, value := label.GetName(), label.GetValue()
if value != magicString {
continue
}
if name == "code" || name == "method" {
continue
}
panic("metric partitioned with non-supported labels")
}
code = true
method = true
return
}
panic("metric partitioned with non-supported labels")
}

View File

@ -23,6 +23,8 @@ import (
)
func TestMiddlewareAPI(t *testing.T) {
reg := prometheus.NewRegistry()
inFlightGauge := prometheus.NewGauge(prometheus.GaugeOpts{
Name: "in_flight_requests",
Help: "A gauge of requests currently being served by the wrapped handler.",
@ -38,9 +40,10 @@ func TestMiddlewareAPI(t *testing.T) {
histVec := prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "response_duration_seconds",
Help: "A histogram of request latencies.",
Buckets: prometheus.DefBuckets,
Name: "response_duration_seconds",
Help: "A histogram of request latencies.",
Buckets: prometheus.DefBuckets,
ConstLabels: prometheus.Labels{"handler": "api"},
},
[]string{"method"},
)
@ -58,7 +61,7 @@ func TestMiddlewareAPI(t *testing.T) {
w.Write([]byte("OK"))
})
prometheus.MustRegister(inFlightGauge, counter, histVec, responseSize)
reg.MustRegister(inFlightGauge, counter, histVec, responseSize)
chain := InstrumentHandlerInFlight(inFlightGauge,
InstrumentHandlerCounter(counter,
@ -87,29 +90,25 @@ func ExampleInstrumentHandlerDuration() {
[]string{"code", "method"},
)
// pushVec is partitioned by the HTTP method and uses custom buckets based on
// the expected request duration. It uses ConstLabels to set a handler label
// marking pushVec as tracking the durations for pushes.
// pushVec and pullVec are partitioned by the HTTP method and use custom
// buckets based on the expected request duration. ConstLabels are used
// to set a handler label to mark pushVec as tracking the durations for
// pushes and pullVec as tracking the durations for pulls. Note that
// Name, Help, and Buckets need to be the same for consistency, so we
// use the same HistogramOpts after just modifying the ConstLabels.
histogramOpts := prometheus.HistogramOpts{
Name: "request_duration_seconds",
Help: "A histogram of latencies for requests.",
Buckets: []float64{.25, .5, 1, 2.5, 5, 10},
ConstLabels: prometheus.Labels{"handler": "push"},
}
pushVec := prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "request_duration_seconds",
Help: "A histogram of latencies for requests to the push handler.",
Buckets: []float64{.25, .5, 1, 2.5, 5, 10},
ConstLabels: prometheus.Labels{"handler": "push"},
},
histogramOpts,
[]string{"method"},
)
// pullVec is also partitioned by the HTTP method but uses custom buckets
// different from those for pushVec. It also has a different value for the
// constant "handler" label.
histogramOpts.ConstLabels = prometheus.Labels{"handler": "pull"}
pullVec := prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "request_duration_seconds",
Help: "A histogram of latencies for requests to the pull handler.",
Buckets: []float64{.005, .01, .025, .05},
ConstLabels: prometheus.Labels{"handler": "pull"},
},
histogramOpts,
[]string{"method"},
)