@@ -63,7 +63,7 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) ht
6363 if code {
6464 return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
6565 now := time .Now ()
66- d := newDelegator (w )
66+ d := newDelegator (w , nil )
6767 next .ServeHTTP (d , r )
6868
6969 obs .With (labels (code , method , r .Method , d .Status ())).Observe (time .Since (now ).Seconds ())
@@ -96,7 +96,7 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler)
9696
9797 if code {
9898 return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
99- d := newDelegator (w )
99+ d := newDelegator (w , nil )
100100 next .ServeHTTP (d , r )
101101 counter .With (labels (code , method , r .Method , d .Status ())).Inc ()
102102 })
@@ -108,6 +108,34 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler)
108108 })
109109}
110110
111+ // InstrumentHandlerTimeToWriteHeader is a middleware that wraps the provided
112+ // http.Handler to observe with the provided ObserverVec the request duration
113+ // until the response headers are written. The ObserverVec must have zero, one,
114+ // or two labels. The only allowed label names are "code" and "method". The
115+ // function panics if any other instance labels are provided. The Observe
116+ // method of the Observer in the ObserverVec is called with the request
117+ // duration in seconds. Partitioning happens by HTTP status code and/or HTTP
118+ // method if the respective instance label names are present in the
119+ // ObserverVec. For unpartitioned observations, use an ObserverVec with zero
120+ // labels. Note that partitioning of Histograms is expensive and should be used
121+ // judiciously.
122+ //
123+ // If the wrapped Handler panics before calling WriteHeader, no value is
124+ // reported.
125+ //
126+ // See the example for InstrumentHandlerDuration for example usage.
127+ func InstrumentHandlerTimeToWriteHeader (obs prometheus.ObserverVec , next http.Handler ) http.HandlerFunc {
128+ code , method := checkLabels (obs )
129+
130+ return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
131+ now := time .Now ()
132+ d := newDelegator (w , func (status int ) {
133+ obs .With (labels (code , method , r .Method , status )).Observe (time .Since (now ).Seconds ())
134+ })
135+ next .ServeHTTP (d , r )
136+ })
137+ }
138+
111139// InstrumentHandlerRequestSize is a middleware that wraps the provided
112140// http.Handler to observe the request size with the provided ObserverVec.
113141// The ObserverVec must have zero, one, or two labels. The only allowed label
@@ -129,7 +157,7 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler)
129157
130158 if code {
131159 return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
132- d := newDelegator (w )
160+ d := newDelegator (w , nil )
133161 next .ServeHTTP (d , r )
134162 size := computeApproximateRequestSize (r )
135163 obs .With (labels (code , method , r .Method , d .Status ())).Observe (float64 (size ))
@@ -162,7 +190,7 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler)
162190func InstrumentHandlerResponseSize (obs prometheus.ObserverVec , next http.Handler ) http.Handler {
163191 code , method := checkLabels (obs )
164192 return http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
165- d := newDelegator (w )
193+ d := newDelegator (w , nil )
166194 next .ServeHTTP (d , r )
167195 obs .With (labels (code , method , r .Method , d .Status ())).Observe (float64 (d .Written ()))
168196 })
@@ -418,10 +446,11 @@ type delegator interface {
418446type responseWriterDelegator struct {
419447 http.ResponseWriter
420448
421- handler , method string
422- status int
423- written int64
424- wroteHeader bool
449+ handler , method string
450+ status int
451+ written int64
452+ wroteHeader bool
453+ observeWriteHeader func (int )
425454}
426455
427456func (r * responseWriterDelegator ) Status () int {
@@ -436,6 +465,9 @@ func (r *responseWriterDelegator) WriteHeader(code int) {
436465 r .status = code
437466 r .wroteHeader = true
438467 r .ResponseWriter .WriteHeader (code )
468+ if r .observeWriteHeader != nil {
469+ r .observeWriteHeader (code )
470+ }
439471}
440472
441473func (r * responseWriterDelegator ) Write (b []byte ) (int , error ) {
0 commit comments