@@ -53,19 +53,10 @@ const (
53
53
acceptEncodingHeader = "Accept-Encoding"
54
54
)
55
55
56
- var bufPool sync.Pool
57
-
58
- func getBuf () * bytes.Buffer {
59
- buf := bufPool .Get ()
60
- if buf == nil {
61
- return & bytes.Buffer {}
62
- }
63
- return buf .(* bytes.Buffer )
64
- }
65
-
66
- func giveBuf (buf * bytes.Buffer ) {
67
- buf .Reset ()
68
- bufPool .Put (buf )
56
+ var gzipPool = sync.Pool {
57
+ New : func () interface {} {
58
+ return gzip .NewWriter (nil )
59
+ },
69
60
}
70
61
71
62
// Handler returns an http.Handler for the prometheus.DefaultGatherer, using
@@ -133,10 +124,9 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
133
124
}
134
125
135
126
contentType := expfmt .Negotiate (req .Header )
136
- buf := getBuf ()
137
- defer giveBuf (buf )
138
- writer , encoding := decorateWriter (req , buf , opts .DisableCompression )
139
- enc := expfmt .NewEncoder (writer , contentType )
127
+ buf := & bytes.Buffer {}
128
+ enc := expfmt .NewEncoder (buf , contentType )
129
+
140
130
var lastErr error
141
131
for _ , mf := range mfs {
142
132
if err := enc .Encode (mf ); err != nil {
@@ -155,29 +145,50 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler {
155
145
}
156
146
}
157
147
}
158
- if closer , ok := writer .(io.Closer ); ok {
159
- closer .Close ()
160
- }
148
+
161
149
if lastErr != nil && buf .Len () == 0 {
162
150
http .Error (w , "No metrics encoded, last error:\n \n " + lastErr .Error (), http .StatusInternalServerError )
163
151
return
164
152
}
165
- header := w .Header ()
166
- header .Set (contentTypeHeader , string (contentType ))
167
- header .Set (contentLengthHeader , fmt .Sprint (buf .Len ()))
168
- if encoding != "" {
169
- header .Set (contentEncodingHeader , encoding )
170
- }
153
+
154
+ w .Header ().Set (contentTypeHeader , string (contentType ))
155
+
171
156
if _ , err := w .Write (buf .Bytes ()); err != nil && opts .ErrorLog != nil {
172
157
opts .ErrorLog .Println ("error while sending encoded metrics:" , err )
173
158
}
174
159
// TODO(beorn7): Consider streaming serving of metrics.
175
160
})
176
161
162
+ gzipHandler := http .HandlerFunc (func (w http.ResponseWriter , req * http.Request ) {
163
+ if opts .DisableCompression {
164
+ h .ServeHTTP (w , req )
165
+ return
166
+ }
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
186
+ })
187
+
177
188
if opts .Timeout <= 0 {
178
- return h
189
+ return gzipHandler
179
190
}
180
- return http .TimeoutHandler (h , opts .Timeout , fmt .Sprintf (
191
+ return http .TimeoutHandler (gzipHandler , opts .Timeout , fmt .Sprintf (
181
192
"Exceeded configured timeout of %v.\n " ,
182
193
opts .Timeout ,
183
194
))
@@ -292,20 +303,13 @@ type HandlerOpts struct {
292
303
Timeout time.Duration
293
304
}
294
305
295
- // decorateWriter wraps a writer to handle gzip compression if requested. It
296
- // returns the decorated writer and the appropriate "Content-Encoding" header
297
- // (which is empty if no compression is enabled).
298
- func decorateWriter (request * http.Request , writer io.Writer , compressionDisabled bool ) (io.Writer , string ) {
299
- if compressionDisabled {
300
- return writer , ""
301
- }
302
- header := request .Header .Get (acceptEncodingHeader )
303
- parts := strings .Split (header , "," )
304
- for _ , part := range parts {
305
- part = strings .TrimSpace (part )
306
- if part == "gzip" || strings .HasPrefix (part , "gzip;" ) {
307
- return gzip .NewWriter (writer ), "gzip"
308
- }
309
- }
310
- return writer , ""
306
+ // gzipResponseWriter in charge of wrapping io.Writer and http.ReponseWriter
307
+ // together, allowing to get a single struct which implements both interface.
308
+ type gzipResponseWriter struct {
309
+ io.Writer
310
+ http.ResponseWriter
311
+ }
312
+
313
+ func (w gzipResponseWriter ) Write (b []byte ) (int , error ) {
314
+ return w .Writer .Write (b )
311
315
}
0 commit comments