github.com/weaveworks/common@v0.0.0-20230728070032-dd9e68f319d5/http/client/client.go (about) 1 package client 2 3 import ( 4 "context" 5 "fmt" 6 "net/http" 7 "strconv" 8 9 "github.com/prometheus/client_golang/prometheus" 10 11 "github.com/weaveworks/common/instrument" 12 ) 13 14 // Requester executes an HTTP request. 15 type Requester interface { 16 Do(req *http.Request) (*http.Response, error) 17 } 18 19 // TimedClient instruments a request. It implements Requester. 20 type TimedClient struct { 21 client Requester 22 collector instrument.Collector 23 } 24 25 type contextKey int 26 27 // OperationNameContextKey specifies the operation name location within the context 28 // for instrumentation. 29 const OperationNameContextKey contextKey = 0 30 31 // NewTimedClient creates a Requester that instruments requests on `client`. 32 func NewTimedClient(client Requester, collector instrument.Collector) *TimedClient { 33 return &TimedClient{ 34 client: client, 35 collector: collector, 36 } 37 } 38 39 // Do executes the request. 40 func (c TimedClient) Do(r *http.Request) (*http.Response, error) { 41 return TimeRequest(r.Context(), c.operationName(r), c.collector, c.client, r) 42 } 43 44 func (c TimedClient) operationName(r *http.Request) string { 45 operation, _ := r.Context().Value(OperationNameContextKey).(string) 46 if operation == "" { 47 operation = r.URL.Path 48 } 49 return operation 50 } 51 52 // TimeRequest performs an HTTP client request and records the duration in a histogram. 53 func TimeRequest(ctx context.Context, operation string, coll instrument.Collector, client Requester, request *http.Request) (*http.Response, error) { 54 var response *http.Response 55 doRequest := func(_ context.Context) error { 56 var err error 57 response, err = client.Do(request) 58 return err 59 } 60 toStatusCode := func(err error) string { 61 if err == nil { 62 return strconv.Itoa(response.StatusCode) 63 } 64 return "error" 65 } 66 err := instrument.CollectedRequest(ctx, fmt.Sprintf("%s %s", request.Method, operation), 67 coll, toStatusCode, doRequest) 68 return response, err 69 } 70 71 // TimeRequestHistogram performs an HTTP client request and records the duration in a histogram. 72 // Deprecated: try to use TimeRequest() to avoid creation of a collector on every request 73 func TimeRequestHistogram(ctx context.Context, operation string, metric *prometheus.HistogramVec, client Requester, request *http.Request) (*http.Response, error) { 74 coll := instrument.NewHistogramCollector(metric) 75 return TimeRequest(ctx, operation, coll, client, request) 76 }