@@ -45,7 +45,10 @@ func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handl
4545// http.Handler to observe the request duration with the provided ObserverVec. 
4646// The ObserverVec must have valid metric and label names and must have zero, 
4747// one, or two non-const non-curried labels. For those, the only allowed label 
48- // names are "code" and "method". The function panics otherwise. The Observe 
48+ // names are "code" and "method". The function panics otherwise. For the "method" 
49+ // label a predefined default label value set is used to filter given values. 
50+ // Values besides predefined values will count as `unknown` method. 
51+ //`WithExtraMethods` can be used to add more methods to the set. The Observe 
4952// method of the Observer in the ObserverVec is called with the request duration 
5053// in seconds. Partitioning happens by HTTP status code and/or HTTP method if 
5154// the respective instance label names are present in the ObserverVec. For 
@@ -58,7 +61,12 @@ func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handl
5861// 
5962// Note that this method is only guaranteed to never observe negative durations 
6063// if used with Go1.9+. 
61- func  InstrumentHandlerDuration (obs  prometheus.ObserverVec , next  http.Handler ) http.HandlerFunc  {
64+ func  InstrumentHandlerDuration (obs  prometheus.ObserverVec , next  http.Handler , opts  ... Option ) http.HandlerFunc  {
65+ 	mwOpts  :=  & option {}
66+ 	for  _ , o  :=  range  opts  {
67+ 		o (mwOpts )
68+ 	}
69+ 
6270	code , method  :=  checkLabels (obs )
6371
6472	if  code  {
@@ -67,22 +75,25 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) ht
6775			d  :=  newDelegator (w , nil )
6876			next .ServeHTTP (d , r )
6977
70- 			obs .With (labels (code , method , r .Method , d .Status ())).Observe (time .Since (now ).Seconds ())
78+ 			obs .With (labels (code , method , r .Method , d .Status (),  mwOpts . extraMethods ... )).Observe (time .Since (now ).Seconds ())
7179		})
7280	}
7381
7482	return  http .HandlerFunc (func (w  http.ResponseWriter , r  * http.Request ) {
7583		now  :=  time .Now ()
7684		next .ServeHTTP (w , r )
77- 		obs .With (labels (code , method , r .Method , 0 )).Observe (time .Since (now ).Seconds ())
85+ 		obs .With (labels (code , method , r .Method , 0 ,  mwOpts . extraMethods ... )).Observe (time .Since (now ).Seconds ())
7886	})
7987}
8088
8189// InstrumentHandlerCounter is a middleware that wraps the provided http.Handler 
8290// to observe the request result with the provided CounterVec. The CounterVec 
8391// must have valid metric and label names and must have zero, one, or two 
8492// non-const non-curried labels. For those, the only allowed label names are 
85- // "code" and "method". The function panics otherwise. Partitioning of the 
93+ // "code" and "method". The function panics otherwise. For the "method" 
94+ // label a predefined default label value set is used to filter given values. 
95+ // Values besides predefined values will count as `unknown` method. 
96+ // `WithExtraMethods` can be used to add more methods to the set. Partitioning of the 
8697// CounterVec happens by HTTP status code and/or HTTP method if the respective 
8798// instance label names are present in the CounterVec. For unpartitioned 
8899// counting, use a CounterVec with zero labels. 
@@ -92,20 +103,25 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) ht
92103// If the wrapped Handler panics, the Counter is not incremented. 
93104// 
94105// See the example for InstrumentHandlerDuration for example usage. 
95- func  InstrumentHandlerCounter (counter  * prometheus.CounterVec , next  http.Handler ) http.HandlerFunc  {
106+ func  InstrumentHandlerCounter (counter  * prometheus.CounterVec , next  http.Handler , opts  ... Option ) http.HandlerFunc  {
107+ 	mwOpts  :=  & option {}
108+ 	for  _ , o  :=  range  opts  {
109+ 		o (mwOpts )
110+ 	}
111+ 
96112	code , method  :=  checkLabels (counter )
97113
98114	if  code  {
99115		return  http .HandlerFunc (func (w  http.ResponseWriter , r  * http.Request ) {
100116			d  :=  newDelegator (w , nil )
101117			next .ServeHTTP (d , r )
102- 			counter .With (labels (code , method , r .Method , d .Status ())).Inc ()
118+ 			counter .With (labels (code , method , r .Method , d .Status (),  mwOpts . extraMethods ... )).Inc ()
103119		})
104120	}
105121
106122	return  http .HandlerFunc (func (w  http.ResponseWriter , r  * http.Request ) {
107123		next .ServeHTTP (w , r )
108- 		counter .With (labels (code , method , r .Method , 0 )).Inc ()
124+ 		counter .With (labels (code , method , r .Method , 0 ,  mwOpts . extraMethods ... )).Inc ()
109125	})
110126}
111127
@@ -114,7 +130,10 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler)
114130// until the response headers are written. The ObserverVec must have valid 
115131// metric and label names and must have zero, one, or two non-const non-curried 
116132// labels. For those, the only allowed label names are "code" and "method". The 
117- // function panics otherwise. The Observe method of the Observer in the 
133+ // function panics otherwise. For the "method" label a predefined default label 
134+ // value set is used to filter given values. Values besides predefined values 
135+ // will count as `unknown` method.`WithExtraMethods` can be used to add more 
136+ // methods to the set. The Observe method of the Observer in the 
118137// ObserverVec is called with the request duration in seconds. Partitioning 
119138// happens by HTTP status code and/or HTTP method if the respective instance 
120139// label names are present in the ObserverVec. For unpartitioned observations, 
@@ -128,13 +147,18 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler)
128147// if used with Go1.9+. 
129148// 
130149// See the example for InstrumentHandlerDuration for example usage. 
131- func  InstrumentHandlerTimeToWriteHeader (obs  prometheus.ObserverVec , next  http.Handler ) http.HandlerFunc  {
150+ func  InstrumentHandlerTimeToWriteHeader (obs  prometheus.ObserverVec , next  http.Handler , opts  ... Option ) http.HandlerFunc  {
151+ 	mwOpts  :=  & option {}
152+ 	for  _ , o  :=  range  opts  {
153+ 		o (mwOpts )
154+ 	}
155+ 
132156	code , method  :=  checkLabels (obs )
133157
134158	return  http .HandlerFunc (func (w  http.ResponseWriter , r  * http.Request ) {
135159		now  :=  time .Now ()
136160		d  :=  newDelegator (w , func (status  int ) {
137- 			obs .With (labels (code , method , r .Method , status )).Observe (time .Since (now ).Seconds ())
161+ 			obs .With (labels (code , method , r .Method , status ,  mwOpts . extraMethods ... )).Observe (time .Since (now ).Seconds ())
138162		})
139163		next .ServeHTTP (d , r )
140164	})
@@ -144,8 +168,11 @@ func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Ha
144168// http.Handler to observe the request size with the provided ObserverVec. The 
145169// ObserverVec must have valid metric and label names and must have zero, one, 
146170// or two non-const non-curried labels. For those, the only allowed label names 
147- // are "code" and "method". The function panics otherwise. The Observe method of 
148- // the Observer in the ObserverVec is called with the request size in 
171+ // are "code" and "method". The function panics otherwise. For the "method" 
172+ // label a predefined default label value set is used to filter given values. 
173+ // Values besides predefined values will count as `unknown` method. 
174+ // `WithExtraMethods` can be used to add more methods to the set. The Observe 
175+ // method of the Observer in the ObserverVec is called with the request size in 
149176// bytes. Partitioning happens by HTTP status code and/or HTTP method if the 
150177// respective instance label names are present in the ObserverVec. For 
151178// unpartitioned observations, use an ObserverVec with zero labels. Note that 
@@ -156,31 +183,39 @@ func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Ha
156183// If the wrapped Handler panics, no values are reported. 
157184// 
158185// See the example for InstrumentHandlerDuration for example usage. 
159- func  InstrumentHandlerRequestSize (obs  prometheus.ObserverVec , next  http.Handler ) http.HandlerFunc  {
186+ func  InstrumentHandlerRequestSize (obs  prometheus.ObserverVec , next  http.Handler , opts  ... Option ) http.HandlerFunc  {
187+ 	mwOpts  :=  & option {}
188+ 	for  _ , o  :=  range  opts  {
189+ 		o (mwOpts )
190+ 	}
191+ 
160192	code , method  :=  checkLabels (obs )
161193
162194	if  code  {
163195		return  http .HandlerFunc (func (w  http.ResponseWriter , r  * http.Request ) {
164196			d  :=  newDelegator (w , nil )
165197			next .ServeHTTP (d , r )
166198			size  :=  computeApproximateRequestSize (r )
167- 			obs .With (labels (code , method , r .Method , d .Status ())).Observe (float64 (size ))
199+ 			obs .With (labels (code , method , r .Method , d .Status (),  mwOpts . extraMethods ... )).Observe (float64 (size ))
168200		})
169201	}
170202
171203	return  http .HandlerFunc (func (w  http.ResponseWriter , r  * http.Request ) {
172204		next .ServeHTTP (w , r )
173205		size  :=  computeApproximateRequestSize (r )
174- 		obs .With (labels (code , method , r .Method , 0 )).Observe (float64 (size ))
206+ 		obs .With (labels (code , method , r .Method , 0 ,  mwOpts . extraMethods ... )).Observe (float64 (size ))
175207	})
176208}
177209
178210// InstrumentHandlerResponseSize is a middleware that wraps the provided 
179211// http.Handler to observe the response size with the provided ObserverVec. The 
180212// ObserverVec must have valid metric and label names and must have zero, one, 
181213// or two non-const non-curried labels. For those, the only allowed label names 
182- // are "code" and "method". The function panics otherwise. The Observe method of 
183- // the Observer in the ObserverVec is called with the response size in 
214+ // are "code" and "method". The function panics otherwise. For the "method" 
215+ // label a predefined default label value set is used to filter given values. 
216+ // Values besides predefined values will count as `unknown` method. 
217+ // `WithExtraMethods` can be used to add more methods to the set. The Observe 
218+ // method of the Observer in the ObserverVec is called with the response size in 
184219// bytes. Partitioning happens by HTTP status code and/or HTTP method if the 
185220// respective instance label names are present in the ObserverVec. For 
186221// unpartitioned observations, use an ObserverVec with zero labels. Note that 
@@ -191,12 +226,18 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler)
191226// If the wrapped Handler panics, no values are reported. 
192227// 
193228// See the example for InstrumentHandlerDuration for example usage. 
194- func  InstrumentHandlerResponseSize (obs  prometheus.ObserverVec , next  http.Handler ) http.Handler  {
229+ func  InstrumentHandlerResponseSize (obs  prometheus.ObserverVec , next  http.Handler , opts  ... Option ) http.Handler  {
230+ 	mwOpts  :=  & option {}
231+ 	for  _ , o  :=  range  opts  {
232+ 		o (mwOpts )
233+ 	}
234+ 
195235	code , method  :=  checkLabels (obs )
236+ 
196237	return  http .HandlerFunc (func (w  http.ResponseWriter , r  * http.Request ) {
197238		d  :=  newDelegator (w , nil )
198239		next .ServeHTTP (d , r )
199- 		obs .With (labels (code , method , r .Method , d .Status ())).Observe (float64 (d .Written ()))
240+ 		obs .With (labels (code , method , r .Method , d .Status (),  mwOpts . extraMethods ... )).Observe (float64 (d .Written ()))
200241	})
201242}
202243
@@ -290,7 +331,7 @@ func isLabelCurried(c prometheus.Collector, label string) bool {
290331// unnecessary allocations on each request. 
291332var  emptyLabels  =  prometheus.Labels {}
292333
293- func  labels (code , method  bool , reqMethod  string , status  int ) prometheus.Labels  {
334+ func  labels (code , method  bool , reqMethod  string , status  int ,  extraMethods   ... string ) prometheus.Labels  {
294335	if  ! (code  ||  method ) {
295336		return  emptyLabels 
296337	}
@@ -300,7 +341,7 @@ func labels(code, method bool, reqMethod string, status int) prometheus.Labels {
300341		labels ["code" ] =  sanitizeCode (status )
301342	}
302343	if  method  {
303- 		labels ["method" ] =  sanitizeMethod (reqMethod )
344+ 		labels ["method" ] =  sanitizeMethod (reqMethod ,  extraMethods ... )
304345	}
305346
306347	return  labels 
@@ -330,7 +371,12 @@ func computeApproximateRequestSize(r *http.Request) int {
330371	return  s 
331372}
332373
333- func  sanitizeMethod (m  string ) string  {
374+ // If the wrapped http.Handler has a known method, it will be sanitized and returned. 
375+ // Otherwise, "unknown" will be returned. The known method list can be extended 
376+ // as needed by using extraMethods parameter. 
377+ func  sanitizeMethod (m  string , extraMethods  ... string ) string  {
378+ 	// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods for 
379+ 	// the methods chosen as default. 
334380	switch  m  {
335381	case  "GET" , "get" :
336382		return  "get" 
@@ -348,15 +394,25 @@ func sanitizeMethod(m string) string {
348394		return  "options" 
349395	case  "NOTIFY" , "notify" :
350396		return  "notify" 
397+ 	case  "TRACE" , "trace" :
398+ 		return  "trace" 
399+ 	case  "PATCH" , "patch" :
400+ 		return  "patch" 
351401	default :
352- 		return  strings .ToLower (m )
402+ 		for  _ , method  :=  range  extraMethods  {
403+ 			if  strings .EqualFold (m , method ) {
404+ 				return  strings .ToLower (m )
405+ 			}
406+ 		}
407+ 		return  "unknown" 
353408	}
354409}
355410
356411// If the wrapped http.Handler has not set a status code, i.e. the value is 
357- // currently 0, santizeCode  will return 200, for consistency with behavior in 
412+ // currently 0, sanitizeCode  will return 200, for consistency with behavior in 
358413// the stdlib. 
359414func  sanitizeCode (s  int ) string  {
415+ 	// See for accepted codes https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml 
360416	switch  s  {
361417	case  100 :
362418		return  "100" 
@@ -453,6 +509,9 @@ func sanitizeCode(s int) string {
453509		return  "511" 
454510
455511	default :
456- 		return  strconv .Itoa (s )
512+ 		if  s  >=  100  &&  s  <=  599  {
513+ 			return  strconv .Itoa (s )
514+ 		}
515+ 		return  "unknown" 
457516	}
458517}
0 commit comments