1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| package httpmetrics
import ( "strconv" "sync" "time"
"github.com/fasthttp/router" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/valyala/fasthttp" "github.com/valyala/fasthttp/fasthttpadaptor"
"{{{ .Package }}}/app/util" )
var ( defaultMetricPath = "/metrics" requestHandlerPool sync.Pool )
func prometheusHandler() fasthttp.RequestHandler { return fasthttpadaptor.NewFastHTTPHandler(promhttp.Handler()) }
func (p *Metrics) WrapHandler(r *router.Router, includeMetrics bool) fasthttp.RequestHandler { if includeMetrics { r.GET(p.MetricsPath, prometheusHandler()) } return func(rc *fasthttp.RequestCtx) { if includeMetrics && string(rc.Request.URI().Path()) == defaultMetricPath { r.Handler(rc) return } reqBytes := make(chan int) frc := acquireRequestFromPool() rc.Request.CopyTo(frc) go computeApproximateRequestSize(frc, reqBytes)
start := util.TimeCurrent() r.Handler(rc)
status := strconv.Itoa(rc.Response.StatusCode()) elapsed := float64(time.Since(start)) / float64(time.Second) rspBytes := float64(len(rc.Response.Body()))
reqDur.WithLabelValues(p.Key, status).Observe(elapsed) reqCnt.WithLabelValues(p.Key, status, string(rc.Method())).Inc() reqSize.Observe(float64(<-reqBytes)) rspSize.Observe(rspBytes) } }
func computeApproximateRequestSize(rc *fasthttp.Request, out chan int) { s := 0 if rc.URI() != nil { s += len(rc.URI().Path()) s += len(rc.URI().Host()) } s += len(rc.Header.Method()) s += len("HTTP/1.1") rc.Header.VisitAll(func(key []byte, value []byte) { if string(key) != "Host" { s += len(key) + len(value) } }) if rc.Header.ContentLength() != -1 { s += rc.Header.ContentLength() } out <- s }
func acquireRequestFromPool() *fasthttp.Request { rp := requestHandlerPool.Get() if rp == nil { return &fasthttp.Request{} } frc, _ := rp.(*fasthttp.Request) return frc }
|