blob: 86fd564470f8161f9696beab0bb51d00c69d1c1b [file] [log] [blame]
khenaidooffe076b2019-01-15 16:08:08 -05001// Copyright 2017 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package promhttp
15
16import (
17 "net/http"
18 "time"
19
20 "github.com/prometheus/client_golang/prometheus"
21)
22
23// The RoundTripperFunc type is an adapter to allow the use of ordinary
24// functions as RoundTrippers. If f is a function with the appropriate
25// signature, RountTripperFunc(f) is a RoundTripper that calls f.
26type RoundTripperFunc func(req *http.Request) (*http.Response, error)
27
28// RoundTrip implements the RoundTripper interface.
29func (rt RoundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) {
30 return rt(r)
31}
32
33// InstrumentRoundTripperInFlight is a middleware that wraps the provided
34// http.RoundTripper. It sets the provided prometheus.Gauge to the number of
35// requests currently handled by the wrapped http.RoundTripper.
36//
37// See the example for ExampleInstrumentRoundTripperDuration for example usage.
38func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripper) RoundTripperFunc {
39 return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
40 gauge.Inc()
41 defer gauge.Dec()
42 return next.RoundTrip(r)
43 })
44}
45
46// InstrumentRoundTripperCounter is a middleware that wraps the provided
47// http.RoundTripper to observe the request result with the provided CounterVec.
48// The CounterVec must have zero, one, or two non-const non-curried labels. For
49// those, the only allowed label names are "code" and "method". The function
50// panics otherwise. Partitioning of the CounterVec happens by HTTP status code
51// and/or HTTP method if the respective instance label names are present in the
52// CounterVec. For unpartitioned counting, use a CounterVec with zero labels.
53//
54// If the wrapped RoundTripper panics or returns a non-nil error, the Counter
55// is not incremented.
56//
57// See the example for ExampleInstrumentRoundTripperDuration for example usage.
58func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper) RoundTripperFunc {
59 code, method := checkLabels(counter)
60
61 return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
62 resp, err := next.RoundTrip(r)
63 if err == nil {
64 counter.With(labels(code, method, r.Method, resp.StatusCode)).Inc()
65 }
66 return resp, err
67 })
68}
69
70// InstrumentRoundTripperDuration is a middleware that wraps the provided
71// http.RoundTripper to observe the request duration with the provided
72// ObserverVec. The ObserverVec must have zero, one, or two non-const
73// non-curried labels. For those, the only allowed label names are "code" and
74// "method". The function panics otherwise. The Observe method of the Observer
75// in the ObserverVec is called with the request duration in
76// seconds. Partitioning happens by HTTP status code and/or HTTP method if the
77// respective instance label names are present in the ObserverVec. For
78// unpartitioned observations, use an ObserverVec with zero labels. Note that
79// partitioning of Histograms is expensive and should be used judiciously.
80//
81// If the wrapped RoundTripper panics or returns a non-nil error, no values are
82// reported.
83//
84// Note that this method is only guaranteed to never observe negative durations
85// if used with Go1.9+.
86func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper) RoundTripperFunc {
87 code, method := checkLabels(obs)
88
89 return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
90 start := time.Now()
91 resp, err := next.RoundTrip(r)
92 if err == nil {
93 obs.With(labels(code, method, r.Method, resp.StatusCode)).Observe(time.Since(start).Seconds())
94 }
95 return resp, err
96 })
97}