@@ -16,6 +16,7 @@ package promhttp
16
16
import (
17
17
"bytes"
18
18
"errors"
19
+ "fmt"
19
20
"log"
20
21
"net/http"
21
22
"net/http/httptest"
@@ -24,6 +25,7 @@ import (
24
25
"time"
25
26
26
27
"github.com/prometheus/client_golang/prometheus"
28
+ dto "github.com/prometheus/client_model/go"
27
29
)
28
30
29
31
type errorCollector struct {}
@@ -56,8 +58,19 @@ func (b blockingCollector) Collect(ch chan<- prometheus.Metric) {
56
58
<- b .Block
57
59
}
58
60
59
- func TestHandlerErrorHandling (t * testing.T ) {
61
+ type mockTransactionGatherer struct {
62
+ g prometheus.Gatherer
63
+ gatherInvoked int
64
+ doneInvoked int
65
+ }
60
66
67
+ func (g * mockTransactionGatherer ) Gather () (_ []* dto.MetricFamily , done func (), err error ) {
68
+ g .gatherInvoked ++
69
+ mfs , err := g .g .Gather ()
70
+ return mfs , func () { g .doneInvoked ++ }, err
71
+ }
72
+
73
+ func TestHandlerErrorHandling (t * testing.T ) {
61
74
// Create a registry that collects a MetricFamily with two elements,
62
75
// another with one, and reports an error. Further down, we'll use the
63
76
// same registry in the HandlerOpts.
@@ -90,21 +103,30 @@ func TestHandlerErrorHandling(t *testing.T) {
90
103
request , _ := http .NewRequest ("GET" , "/" , nil )
91
104
request .Header .Add ("Accept" , "test/plain" )
92
105
93
- errorHandler := HandlerFor (reg , HandlerOpts {
106
+ mReg := & mockTransactionGatherer {g : reg }
107
+ errorHandler := HandlerForTransactional (mReg , HandlerOpts {
94
108
ErrorLog : logger ,
95
109
ErrorHandling : HTTPErrorOnError ,
96
110
Registry : reg ,
97
111
})
98
- continueHandler := HandlerFor ( reg , HandlerOpts {
112
+ continueHandler := HandlerForTransactional ( mReg , HandlerOpts {
99
113
ErrorLog : logger ,
100
114
ErrorHandling : ContinueOnError ,
101
115
Registry : reg ,
102
116
})
103
- panicHandler := HandlerFor ( reg , HandlerOpts {
117
+ panicHandler := HandlerForTransactional ( mReg , HandlerOpts {
104
118
ErrorLog : logger ,
105
119
ErrorHandling : PanicOnError ,
106
120
Registry : reg ,
107
121
})
122
+ // Expect gatherer not touched.
123
+ if got := mReg .gatherInvoked ; got != 0 {
124
+ t .Fatalf ("unexpected number of gather invokes, want 0, got %d" , got )
125
+ }
126
+ if got := mReg .doneInvoked ; got != 0 {
127
+ t .Fatalf ("unexpected number of done invokes, want 0, got %d" , got )
128
+ }
129
+
108
130
wantMsg := `error gathering metrics: error collecting metric Desc{fqName: "invalid_metric", help: "not helpful", constLabels: {}, variableLabels: []}: collect error
109
131
`
110
132
wantErrorBody := `An error has occurred while serving metrics:
@@ -140,25 +162,39 @@ the_count 0
140
162
`
141
163
142
164
errorHandler .ServeHTTP (writer , request )
165
+ if got := mReg .gatherInvoked ; got != 1 {
166
+ t .Fatalf ("unexpected number of gather invokes, want 1, got %d" , got )
167
+ }
168
+ if got := mReg .doneInvoked ; got != 1 {
169
+ t .Fatalf ("unexpected number of done invokes, want 1, got %d" , got )
170
+ }
143
171
if got , want := writer .Code , http .StatusInternalServerError ; got != want {
144
172
t .Errorf ("got HTTP status code %d, want %d" , got , want )
145
173
}
146
- if got := logBuf .String (); got != wantMsg {
147
- t .Errorf ("got log message: \n %s \n want log message: \n %s \n " , got , wantMsg )
174
+ if got , want := logBuf .String (), wantMsg ; got != want {
175
+ t .Errorf ("got log buf %q, want %q " , got , want )
148
176
}
149
- if got := writer .Body .String (); got != wantErrorBody {
150
- t .Errorf ("got body: \n %s \n want body: \n %s \n " , got , wantErrorBody )
177
+ if got , want := writer .Body .String (), wantErrorBody ; got != want {
178
+ t .Errorf ("got body %q, want %q " , got , want )
151
179
}
180
+
152
181
logBuf .Reset ()
153
182
writer .Body .Reset ()
154
183
writer .Code = http .StatusOK
155
184
156
185
continueHandler .ServeHTTP (writer , request )
186
+
187
+ if got := mReg .gatherInvoked ; got != 2 {
188
+ t .Fatalf ("unexpected number of gather invokes, want 2, got %d" , got )
189
+ }
190
+ if got := mReg .doneInvoked ; got != 2 {
191
+ t .Fatalf ("unexpected number of done invokes, want 2, got %d" , got )
192
+ }
157
193
if got , want := writer .Code , http .StatusOK ; got != want {
158
194
t .Errorf ("got HTTP status code %d, want %d" , got , want )
159
195
}
160
- if got := logBuf .String (); got != wantMsg {
161
- t .Errorf ("got log message %q, want %q" , got , wantMsg )
196
+ if got , want := logBuf .String (), wantMsg ; got != want {
197
+ t .Errorf ("got log buf %q, want %q" , got , want )
162
198
}
163
199
if got := writer .Body .String (); got != wantOKBody1 && got != wantOKBody2 {
164
200
t .Errorf ("got body %q, want either %q or %q" , got , wantOKBody1 , wantOKBody2 )
@@ -168,20 +204,34 @@ the_count 0
168
204
if err := recover (); err == nil {
169
205
t .Error ("expected panic from panicHandler" )
170
206
}
207
+ if got := mReg .gatherInvoked ; got != 3 {
208
+ t .Fatalf ("unexpected number of gather invokes, want 3, got %d" , got )
209
+ }
210
+ if got := mReg .doneInvoked ; got != 3 {
211
+ t .Fatalf ("unexpected number of done invokes, want 3, got %d" , got )
212
+ }
171
213
}()
172
214
panicHandler .ServeHTTP (writer , request )
173
215
}
174
216
175
217
func TestInstrumentMetricHandler (t * testing.T ) {
176
218
reg := prometheus .NewRegistry ()
177
- handler := InstrumentMetricHandler (reg , HandlerFor (reg , HandlerOpts {}))
219
+ mReg := & mockTransactionGatherer {g : reg }
220
+ handler := InstrumentMetricHandler (reg , HandlerForTransactional (mReg , HandlerOpts {}))
178
221
// Do it again to test idempotency.
179
- InstrumentMetricHandler (reg , HandlerFor ( reg , HandlerOpts {}))
222
+ InstrumentMetricHandler (reg , HandlerForTransactional ( mReg , HandlerOpts {}))
180
223
writer := httptest .NewRecorder ()
181
224
request , _ := http .NewRequest ("GET" , "/" , nil )
182
225
request .Header .Add ("Accept" , "test/plain" )
183
226
184
227
handler .ServeHTTP (writer , request )
228
+ if got := mReg .gatherInvoked ; got != 1 {
229
+ t .Fatalf ("unexpected number of gather invokes, want 1, got %d" , got )
230
+ }
231
+ if got := mReg .doneInvoked ; got != 1 {
232
+ t .Fatalf ("unexpected number of done invokes, want 1, got %d" , got )
233
+ }
234
+
185
235
if got , want := writer .Code , http .StatusOK ; got != want {
186
236
t .Errorf ("got HTTP status code %d, want %d" , got , want )
187
237
}
@@ -195,19 +245,28 @@ func TestInstrumentMetricHandler(t *testing.T) {
195
245
t .Errorf ("got body %q, does not contain %q" , got , want )
196
246
}
197
247
198
- writer .Body .Reset ()
199
- handler .ServeHTTP (writer , request )
200
- if got , want := writer .Code , http .StatusOK ; got != want {
201
- t .Errorf ("got HTTP status code %d, want %d" , got , want )
202
- }
248
+ for i := 0 ; i < 100 ; i ++ {
249
+ writer .Body .Reset ()
250
+ handler .ServeHTTP (writer , request )
203
251
204
- want = "promhttp_metric_handler_requests_in_flight 1\n "
205
- if got := writer .Body .String (); ! strings .Contains (got , want ) {
206
- t .Errorf ("got body %q, does not contain %q" , got , want )
207
- }
208
- want = "promhttp_metric_handler_requests_total{code=\" 200\" } 1\n "
209
- if got := writer .Body .String (); ! strings .Contains (got , want ) {
210
- t .Errorf ("got body %q, does not contain %q" , got , want )
252
+ if got , want := mReg .gatherInvoked , i + 2 ; got != want {
253
+ t .Fatalf ("unexpected number of gather invokes, want %d, got %d" , want , got )
254
+ }
255
+ if got , want := mReg .doneInvoked , i + 2 ; got != want {
256
+ t .Fatalf ("unexpected number of done invokes, want %d, got %d" , want , got )
257
+ }
258
+ if got , want := writer .Code , http .StatusOK ; got != want {
259
+ t .Errorf ("got HTTP status code %d, want %d" , got , want )
260
+ }
261
+
262
+ want := "promhttp_metric_handler_requests_in_flight 1\n "
263
+ if got := writer .Body .String (); ! strings .Contains (got , want ) {
264
+ t .Errorf ("got body %q, does not contain %q" , got , want )
265
+ }
266
+ want = fmt .Sprintf ("promhttp_metric_handler_requests_total{code=\" 200\" } %d\n " , i + 1 )
267
+ if got := writer .Body .String (); ! strings .Contains (got , want ) {
268
+ t .Errorf ("got body %q, does not contain %q" , got , want )
269
+ }
211
270
}
212
271
}
213
272
0 commit comments