forked from mirror/client_golang
Add a configurable version of InstrumentHandler and InstrumentHandlerFunc.
Also, remove quotes from the Content-type header. It's not illegal to have quotes there, but they are not needed, and at other places, we are not using them. So fewer characters and more consistency. Change-Id: If7a78bde85154163e4426daec493d973213e83e9
This commit is contained in:
parent
23e5e5fefd
commit
96297bcbae
|
@ -20,45 +20,7 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
instLabels = []string{"handler", "method", "code"}
|
||||
|
||||
reqCnt = NewCounterVec(
|
||||
CounterOpts{
|
||||
Subsystem: "http",
|
||||
Name: "requests_total",
|
||||
Help: "Total number of HTTP requests made.",
|
||||
},
|
||||
instLabels,
|
||||
)
|
||||
|
||||
reqDur = NewSummaryVec(
|
||||
SummaryOpts{
|
||||
Subsystem: "http",
|
||||
Name: "request_duration_microseconds",
|
||||
Help: "The HTTP request latencies in microseconds.",
|
||||
},
|
||||
instLabels,
|
||||
)
|
||||
|
||||
reqSz = NewSummaryVec(
|
||||
SummaryOpts{
|
||||
Subsystem: "http",
|
||||
Name: "request_size_bytes",
|
||||
Help: "The HTTP request sizes in bytes.",
|
||||
},
|
||||
instLabels,
|
||||
)
|
||||
|
||||
resSz = NewSummaryVec(
|
||||
SummaryOpts{
|
||||
Subsystem: "http",
|
||||
Name: "response_size_bytes",
|
||||
Help: "The HTTP response sizes in bytes.",
|
||||
},
|
||||
instLabels,
|
||||
)
|
||||
)
|
||||
var instLabels = []string{"method", "code"}
|
||||
|
||||
type nower interface {
|
||||
Now() time.Time
|
||||
|
@ -103,6 +65,71 @@ func InstrumentHandler(handlerName string, handler http.Handler) http.HandlerFun
|
|||
// (SummaryVec). Each has three labels: handler, method, code. The value of the
|
||||
// handler label is set by the handlerName parameter of this function.
|
||||
func InstrumentHandlerFunc(handlerName string, handlerFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
|
||||
return InstrumentHandlerFuncWithOpts(
|
||||
SummaryOpts{
|
||||
Subsystem: "http",
|
||||
ConstLabels: Labels{"handler": handlerName},
|
||||
},
|
||||
handlerFunc,
|
||||
)
|
||||
}
|
||||
|
||||
// InstrumentHandlerWithOpts works like InstrumentHandler but provides more
|
||||
// flexibility (at the cost of a more complex call syntax). As
|
||||
// InstrumentHandler, this function registers four metric vector collectors, but
|
||||
// it uses the provided SummaryOpts to create them. However, the fields "Name"
|
||||
// and "Help" in the SummaryOpts are ignored. "Name" is replaced by
|
||||
// "requests_total", "request_duration_microseconds", "request_size_bytes", and
|
||||
// "response_size_bytes", respectively. "Help" is replaced by an appropriate
|
||||
// help string. The names of the variable labels of the vector collectors are
|
||||
// "method" (get, post, etc.), and "code" (HTTP status code).
|
||||
//
|
||||
// If InstrumentHandlerWithOpts is called as follows, it mimics exactly the
|
||||
// behavior of InstrumentHandler:
|
||||
//
|
||||
// prometheus.InstrumentHandlerWithOpts(
|
||||
// prometheus.SummaryOpts{
|
||||
// Subsystem: "http",
|
||||
// ConstLabels: prometheus.Labels{"handler": handlerName},
|
||||
// },
|
||||
// handler,
|
||||
// )
|
||||
//
|
||||
// Technical detail: "requests_total" is a CounterVec, not a SummaryVec, so it
|
||||
// cannot use SummaryOpts. Instead, a CounterOpts struct is created internally,
|
||||
// and all its fields are set to the equally named fields in the provided
|
||||
// SummaryOpts.
|
||||
func InstrumentHandlerWithOpts(opts SummaryOpts, handler http.Handler) http.HandlerFunc {
|
||||
return InstrumentHandlerFuncWithOpts(opts, handler.ServeHTTP)
|
||||
}
|
||||
|
||||
// InstrumentHandlerFuncWithOpts works like InstrumentHandlerFunc but provides
|
||||
// more flexibility (at the cost of a more complex call syntax). See
|
||||
// InstrumentHandlerWithOpts for details how the provided SummaryOpts are used.
|
||||
func InstrumentHandlerFuncWithOpts(opts SummaryOpts, handlerFunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
|
||||
reqCnt := NewCounterVec(
|
||||
CounterOpts{
|
||||
Namespace: opts.Namespace,
|
||||
Subsystem: opts.Subsystem,
|
||||
Name: "requests_total",
|
||||
Help: "Total number of HTTP requests made.",
|
||||
ConstLabels: opts.ConstLabels,
|
||||
},
|
||||
instLabels,
|
||||
)
|
||||
|
||||
opts.Name = "request_duration_microseconds"
|
||||
opts.Help = "The HTTP request latencies in microseconds."
|
||||
reqDur := NewSummaryVec(opts, instLabels)
|
||||
|
||||
opts.Name = "request_size_bytes"
|
||||
opts.Help = "The HTTP request sizes in bytes."
|
||||
reqSz := NewSummaryVec(opts, instLabels)
|
||||
|
||||
opts.Name = "response_size_bytes"
|
||||
opts.Help = "The HTTP response sizes in bytes."
|
||||
resSz := NewSummaryVec(opts, instLabels)
|
||||
|
||||
regReqCnt := MustRegisterOrGet(reqCnt).(*CounterVec)
|
||||
regReqDur := MustRegisterOrGet(reqDur).(*SummaryVec)
|
||||
regReqSz := MustRegisterOrGet(reqSz).(*SummaryVec)
|
||||
|
@ -120,10 +147,10 @@ func InstrumentHandlerFunc(handlerName string, handlerFunc func(http.ResponseWri
|
|||
|
||||
method := sanitizeMethod(r.Method)
|
||||
code := sanitizeCode(delegate.status)
|
||||
regReqCnt.WithLabelValues(handlerName, method, code).Inc()
|
||||
regReqDur.WithLabelValues(handlerName, method, code).Observe(elapsed)
|
||||
regResSz.WithLabelValues(handlerName, method, code).Observe(float64(delegate.written))
|
||||
regReqSz.WithLabelValues(handlerName, method, code).Observe(float64(<-out))
|
||||
regReqCnt.WithLabelValues(method, code).Inc()
|
||||
regReqDur.WithLabelValues(method, code).Observe(elapsed)
|
||||
regResSz.WithLabelValues(method, code).Observe(float64(delegate.written))
|
||||
regReqSz.WithLabelValues(method, code).Observe(float64(<-out))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -37,15 +37,43 @@ func TestInstrumentHandler(t *testing.T) {
|
|||
instant := time.Now()
|
||||
end := instant.Add(30 * time.Second)
|
||||
now = nowSeries(instant, end)
|
||||
respBody := respBody("Howdy there!")
|
||||
|
||||
hndlr := InstrumentHandler("test-handler", respBody)
|
||||
|
||||
opts := SummaryOpts{
|
||||
Subsystem: "http",
|
||||
ConstLabels: Labels{"handler": "test-handler"},
|
||||
}
|
||||
|
||||
reqCnt := MustRegisterOrGet(NewCounterVec(
|
||||
CounterOpts{
|
||||
Namespace: opts.Namespace,
|
||||
Subsystem: opts.Subsystem,
|
||||
Name: "requests_total",
|
||||
Help: "Total number of HTTP requests made.",
|
||||
ConstLabels: opts.ConstLabels,
|
||||
},
|
||||
instLabels,
|
||||
)).(*CounterVec)
|
||||
|
||||
opts.Name = "request_duration_microseconds"
|
||||
opts.Help = "The HTTP request latencies in microseconds."
|
||||
reqDur := MustRegisterOrGet(NewSummaryVec(opts, instLabels)).(*SummaryVec)
|
||||
|
||||
opts.Name = "request_size_bytes"
|
||||
opts.Help = "The HTTP request sizes in bytes."
|
||||
reqSz := MustRegisterOrGet(NewSummaryVec(opts, instLabels)).(*SummaryVec)
|
||||
|
||||
opts.Name = "response_size_bytes"
|
||||
opts.Help = "The HTTP response sizes in bytes."
|
||||
resSz := MustRegisterOrGet(NewSummaryVec(opts, instLabels)).(*SummaryVec)
|
||||
|
||||
reqCnt.Reset()
|
||||
reqDur.Reset()
|
||||
reqSz.Reset()
|
||||
resSz.Reset()
|
||||
|
||||
respBody := respBody("Howdy there!")
|
||||
|
||||
hndlr := InstrumentHandler("test-handler", respBody)
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req := &http.Request{
|
||||
Method: "GET",
|
||||
|
@ -63,7 +91,7 @@ func TestInstrumentHandler(t *testing.T) {
|
|||
if want, got := 1, len(reqDur.children); want != got {
|
||||
t.Errorf("want %d children in reqDur, got %d", want, got)
|
||||
}
|
||||
sum, err := reqDur.GetMetricWithLabelValues("test-handler", "get", "418")
|
||||
sum, err := reqDur.GetMetricWithLabelValues("get", "418")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -86,7 +114,7 @@ func TestInstrumentHandler(t *testing.T) {
|
|||
if want, got := 1, len(reqCnt.children); want != got {
|
||||
t.Errorf("want %d children in reqCnt, got %d", want, got)
|
||||
}
|
||||
cnt, err := reqCnt.GetMetricWithLabelValues("test-handler", "get", "418")
|
||||
cnt, err := reqCnt.GetMetricWithLabelValues("get", "418")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -55,17 +55,17 @@ const (
|
|||
|
||||
// DelimitedTelemetryContentType is the content type set on telemetry
|
||||
// data responses in delimited protobuf format.
|
||||
DelimitedTelemetryContentType = `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="delimited"`
|
||||
DelimitedTelemetryContentType = `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`
|
||||
// TextTelemetryContentType is the content type set on telemetry data
|
||||
// responses in text format.
|
||||
TextTelemetryContentType = `text/plain; version=` + APIVersion
|
||||
// ProtoTextTelemetryContentType is the content type set on telemetry
|
||||
// data responses in protobuf text format. (Only used for debugging.)
|
||||
ProtoTextTelemetryContentType = `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="text"`
|
||||
ProtoTextTelemetryContentType = `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=text`
|
||||
// ProtoCompactTextTelemetryContentType is the content type set on
|
||||
// telemetry data responses in protobuf compact text format. (Only used
|
||||
// for debugging.)
|
||||
ProtoCompactTextTelemetryContentType = `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="compact-text"`
|
||||
ProtoCompactTextTelemetryContentType = `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=compact-text`
|
||||
|
||||
// Constants for object pools.
|
||||
numBufs = 4
|
||||
|
|
|
@ -266,7 +266,7 @@ metric: <
|
|||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="delimited"`,
|
||||
"Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`,
|
||||
},
|
||||
body: []byte{},
|
||||
},
|
||||
|
@ -289,7 +289,7 @@ metric: <
|
|||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="delimited"`,
|
||||
"Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`,
|
||||
},
|
||||
body: expectedMetricFamilyAsBytes,
|
||||
},
|
||||
|
@ -313,7 +313,7 @@ metric: <
|
|||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="delimited"`,
|
||||
"Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`,
|
||||
},
|
||||
body: externalMetricFamilyAsBytes,
|
||||
},
|
||||
|
@ -325,7 +325,7 @@ metric: <
|
|||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="delimited"`,
|
||||
"Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`,
|
||||
},
|
||||
body: bytes.Join(
|
||||
[][]byte{
|
||||
|
@ -386,7 +386,7 @@ metric: <
|
|||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="delimited"`,
|
||||
"Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`,
|
||||
},
|
||||
body: bytes.Join(
|
||||
[][]byte{
|
||||
|
@ -405,7 +405,7 @@ metric: <
|
|||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="text"`,
|
||||
"Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=text`,
|
||||
},
|
||||
body: bytes.Join(
|
||||
[][]byte{
|
||||
|
@ -424,7 +424,7 @@ metric: <
|
|||
},
|
||||
out: output{
|
||||
headers: map[string]string{
|
||||
"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="compact-text"`,
|
||||
"Content-Type": `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=compact-text`,
|
||||
},
|
||||
body: bytes.Join(
|
||||
[][]byte{
|
||||
|
|
Loading…
Reference in New Issue