Skip to content

Commit

Permalink
Merge pull request #12 from bweston92/feature/status-code-extractor
Browse files Browse the repository at this point in the history
Add status code extractor.
  • Loading branch information
linki authored May 14, 2018
2 parents d0fa295 + 0db8a09 commit 639c8de
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 2 deletions.
22 changes: 20 additions & 2 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import (
"github.com/prometheus/client_golang/prometheus"
)

const (
BogusStatusCode = 999
)

// Transport is a http.RoundTripper that collects Prometheus metrics of every
// request it processes. It allows to be configured with callbacks that process
// request path and query into a suitable label value.
Expand All @@ -23,6 +27,7 @@ type Transport struct {
type Callbacks struct {
PathProcessor func(string) string
QueryProcessor func(string) string
CodeProcessor func(int) string
}

const (
Expand Down Expand Up @@ -52,6 +57,15 @@ var (
parts := strings.Split(path, "/")
return parts[len(parts)-1]
}
// IntToStringProcessor converts an integer value to its string representation.
IntToStringProcessor = func(input int) string { return fmt.Sprintf("%d", input) }
// ServerErrorCodeProcessor exports all failed responses (5xx, timeouts, ...) as status=failure
ServerErrorCodeProcessor = func(code int) string {
if code >= http.StatusInternalServerError {
return "failure"
}
return "success"
}
)

// init registers the Prometheus metric globally when the package is loaded.
Expand All @@ -62,7 +76,7 @@ func init() {
// RoundTrip implements http.RoundTripper. It forwards the request to the
// next RoundTripper and measures the time it took in Prometheus summary.
func (it *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
var statusCode int
statusCode := BogusStatusCode

// Remember the current time.
now := time.Now()
Expand All @@ -80,7 +94,7 @@ func (it *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
it.cbs.PathProcessor(req.URL.Path),
it.cbs.QueryProcessor(req.URL.RawQuery),
req.Method,
fmt.Sprintf("%d", statusCode),
it.cbs.CodeProcessor(statusCode),
).Observe(time.Since(now).Seconds())

// return the response and error reported from the next RoundTripper.
Expand Down Expand Up @@ -123,6 +137,10 @@ func NewTransport(next http.RoundTripper, cbs *Callbacks) http.RoundTripper {
if cbs.QueryProcessor == nil {
cbs.QueryProcessor = EliminatingProcessor
}
// By default, status code is set as is.
if cbs.CodeProcessor == nil {
cbs.CodeProcessor = IntToStringProcessor
}

return &Transport{next: next, cbs: cbs}
}
54 changes: 54 additions & 0 deletions examples/status-code/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package main

import (
"fmt"
"log"
"net/http"
"time"

"github.com/linki/instrumented_http"
"github.com/prometheus/client_golang/prometheus/promhttp"
)

func main() {
go func() {
http.Handle("/metrics", promhttp.Handler())
log.Fatal(http.ListenAndServe("127.0.0.1:9099", nil))
}()

client := instrumented_http.NewClient(nil, &instrumented_http.Callbacks{
PathProcessor: instrumented_http.IdentityProcessor,
QueryProcessor: instrumented_http.IdentityProcessor,
CodeProcessor: func(code int) string {
// export all status codes >= 400 as label status=failure instead of their individual values.
if code >= http.StatusBadRequest {
return "failure"
}
return "success"
},
})

for {
func() {
resp, err := client.Get("https://kubernetes.io/docs/search/?q=pods")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()

fmt.Printf("%d\n", resp.StatusCode)
}()

time.Sleep(10 * time.Second)
}
}

// expected result:
//
// $ curl -Ss 127.0.0.1:9099/metrics | grep http
//
// http_request_duration_seconds{handler="instrumented_http",host="kubernetes.io",method="GET",path="/docs/search/",query="q=pods",scheme="https",status="success",quantile="0.5"} 0.662351
// http_request_duration_seconds{handler="instrumented_http",host="kubernetes.io",method="GET",path="/docs/search/",query="q=pods",scheme="https",status="success",quantile="0.9"} 1.000437
// http_request_duration_seconds{handler="instrumented_http",host="kubernetes.io",method="GET",path="/docs/search/",query="q=pods",scheme="https",status="success",quantile="0.99"} 1.000437
// http_request_duration_seconds_sum{handler="instrumented_http",host="kubernetes.io",method="GET",path="/docs/search/",query="q=pods",scheme="https",status="success"} 1.662788442
// http_request_duration_seconds_count{handler="instrumented_http",host="kubernetes.io",method="GET",path="/docs/search/",query="q=pods",scheme="https",status="success"} 2

0 comments on commit 639c8de

Please sign in to comment.