@@ -59,6 +59,12 @@ var gzipPool = sync.Pool{
59
59
},
60
60
}
61
61
62
+ var bufPool = sync.Pool {
63
+ New : func () interface {} {
64
+ return & bytes.Buffer {}
65
+ },
66
+ }
67
+
62
68
// Handler returns an http.Handler for the prometheus.DefaultGatherer, using
63
69
// default HandlerOpts, i.e. it reports the first error as an HTTP error, it has
64
70
// no error logging, and it applies compression if requested by the client.
@@ -103,7 +109,6 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
103
109
return
104
110
}
105
111
}
106
-
107
112
mfs , err := reg .Gather ()
108
113
if err != nil {
109
114
if opts .ErrorLog != nil {
@@ -124,9 +129,12 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
124
129
}
125
130
126
131
contentType := expfmt .Negotiate (req .Header )
127
- buf := & bytes.Buffer {}
132
+ buf := bufPool .Get ().(* bytes.Buffer )
133
+ buf .Reset ()
128
134
enc := expfmt .NewEncoder (buf , contentType )
129
135
136
+ defer bufPool .Put (buf )
137
+
130
138
var lastErr error
131
139
for _ , mf := range mfs {
132
140
if err := enc .Encode (mf ); err != nil {
@@ -150,45 +158,30 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
150
158
http .Error (w , "No metrics encoded, last error:\n \n " + lastErr .Error (), http .StatusInternalServerError )
151
159
return
152
160
}
161
+ header := w .Header ()
162
+ header .Set (contentTypeHeader , string (contentType ))
163
+ header .Set (contentLengthHeader , fmt .Sprint (buf .Len ()))
153
164
154
- w .Header ().Set (contentTypeHeader , string (contentType ))
165
+ if ! opts .DisableCompression && gzipAccepted (req .Header ) {
166
+ header .Set (contentEncodingHeader , "gzip" )
167
+ gz := gzipPool .Get ().(* gzip.Writer )
168
+ defer gzipPool .Put (gz )
155
169
156
- if _ , err := w .Write (buf .Bytes ()); err != nil && opts .ErrorLog != nil {
157
- opts .ErrorLog .Println ("error while sending encoded metrics:" , err )
158
- }
159
- // TODO(beorn7): Consider streaming serving of metrics.
160
- })
170
+ gz .Reset (w )
171
+ defer gz .Close ()
161
172
162
- gzipHandler := http .HandlerFunc (func (w http.ResponseWriter , req * http.Request ) {
163
- if opts .DisableCompression {
164
- h .ServeHTTP (w , req )
173
+ zipWriter := gzipResponseWriter {gz , w }
174
+ writeResult (zipWriter , buf , opts )
165
175
return
166
176
}
167
- header := req .Header .Get (acceptEncodingHeader )
168
- parts := strings .Split (header , "," )
169
- for _ , part := range parts {
170
- part = strings .TrimSpace (part )
171
- if part == "gzip" || strings .HasPrefix (part , "gzip;" ) {
172
-
173
- w .Header ().Set (contentEncodingHeader , "gzip" )
174
- gz := gzipPool .Get ().(* gzip.Writer )
175
- defer gzipPool .Put (gz )
176
-
177
- gz .Reset (w )
178
- defer gz .Close ()
179
-
180
- h .ServeHTTP (gzipResponseWriter {gz , w }, req )
181
- return
182
- }
183
- }
184
- h .ServeHTTP (w , req )
185
- return
177
+ writeResult (w , buf , opts )
178
+ // TODO(beorn7): Consider streaming serving of metrics.
186
179
})
187
180
188
181
if opts .Timeout <= 0 {
189
- return gzipHandler
182
+ return h
190
183
}
191
- return http .TimeoutHandler (gzipHandler , opts .Timeout , fmt .Sprintf (
184
+ return http .TimeoutHandler (h , opts .Timeout , fmt .Sprintf (
192
185
"Exceeded configured timeout of %v.\n " ,
193
186
opts .Timeout ,
194
187
))
@@ -313,3 +306,26 @@ type gzipResponseWriter struct {
313
306
func (w gzipResponseWriter ) Write (b []byte ) (int , error ) {
314
307
return w .Writer .Write (b )
315
308
}
309
+
310
+ // writeResult to buf using http.ResponseWriter.
311
+ // If ErrorLog is enabled, err is logged in.
312
+ func writeResult (w http.ResponseWriter , buf * bytes.Buffer , opts HandlerOpts ) {
313
+ if _ , err := w .Write (buf .Bytes ()); err != nil && opts .ErrorLog != nil {
314
+ opts .ErrorLog .Println ("error while sending encoded metrics:" , err )
315
+ }
316
+ }
317
+
318
+ // gzipHandler return a http.HandlerFunc in charge of compressing the content
319
+ // of the given http.HandlerFunc
320
+ func gzipAccepted (header http.Header ) bool {
321
+
322
+ a := header .Get (acceptEncodingHeader )
323
+ parts := strings .Split (a , "," )
324
+ for _ , part := range parts {
325
+ part = strings .TrimSpace (part )
326
+ if part == "gzip" || strings .HasPrefix (part , "gzip;" ) {
327
+ return true
328
+ }
329
+ }
330
+ return false
331
+ }
0 commit comments