Skip to content

Commit 0d37899

Browse files
authored
Fix metric middleware panic (#133)
* test: add server_test middleware test * fix: revert to old put/get handler behavior, and fix tests * fix: metric panic * fix: lint
1 parent 842affb commit 0d37899

File tree

3 files changed

+48
-11
lines changed

3 files changed

+48
-11
lines changed

metrics/metrics.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func NewMetrics(subsystem string) *Metrics {
9999
Buckets: prometheus.ExponentialBucketsRange(0.05, 1200, 20),
100100
Help: "Histogram of HTTP server request durations",
101101
}, []string{
102-
"method", "commitment_mode", "DA_cert_version", // no status on histograms because those are very expensive
102+
"method", // no status on histograms because those are very expensive
103103
}),
104104
registry: registry,
105105
factory: factory,

server/server.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -146,19 +146,23 @@ func (svr *Server) Health(w http.ResponseWriter, _ *http.Request) error {
146146
return nil
147147
}
148148

149+
// HandleGet handles the GET request for commitments.
150+
// Note: even when an error is returned, the commitment meta is still returned,
151+
// because it is needed for metrics (see the WithMetrics middleware).
152+
// TODO: we should change this behavior and instead use a custom error that contains the commitment meta.
149153
func (svr *Server) HandleGet(w http.ResponseWriter, r *http.Request) (commitments.CommitmentMeta, error) {
150154
meta, err := ReadCommitmentMeta(r)
151155
if err != nil {
152156
err = fmt.Errorf("invalid commitment mode: %w", err)
153157
svr.WriteBadRequest(w, err)
154-
return commitments.CommitmentMeta{}, err
158+
return meta, err
155159
}
156160
key := path.Base(r.URL.Path)
157161
comm, err := commitments.StringToDecodedCommitment(key, meta.Mode)
158162
if err != nil {
159163
err = fmt.Errorf("failed to decode commitment from key %v (commitment mode %v): %w", key, meta.Mode, err)
160164
svr.WriteBadRequest(w, err)
161-
return commitments.CommitmentMeta{}, err
165+
return meta, err
162166
}
163167

164168
input, err := svr.router.Get(r.Context(), comm, meta.Mode)
@@ -169,26 +173,30 @@ func (svr *Server) HandleGet(w http.ResponseWriter, r *http.Request) (commitment
169173
} else {
170174
svr.WriteInternalError(w, err)
171175
}
172-
return commitments.CommitmentMeta{}, err
176+
return meta, err
173177
}
174178

175179
svr.WriteResponse(w, input)
176180
return meta, nil
177181
}
178182

183+
// HandlePut handles the PUT request for commitments.
184+
// Note: even when an error is returned, the commitment meta is still returned,
185+
// because it is needed for metrics (see the WithMetrics middleware).
186+
// TODO: we should change this behavior and instead use a custom error that contains the commitment meta.
179187
func (svr *Server) HandlePut(w http.ResponseWriter, r *http.Request) (commitments.CommitmentMeta, error) {
180188
meta, err := ReadCommitmentMeta(r)
181189
if err != nil {
182190
err = fmt.Errorf("invalid commitment mode: %w", err)
183191
svr.WriteBadRequest(w, err)
184-
return commitments.CommitmentMeta{}, err
192+
return meta, err
185193
}
186194

187195
input, err := io.ReadAll(r.Body)
188196
if err != nil {
189197
err = fmt.Errorf("failed to read request body: %w", err)
190198
svr.WriteBadRequest(w, err)
191-
return commitments.CommitmentMeta{}, err
199+
return meta, err
192200
}
193201

194202
key := path.Base(r.URL.Path)
@@ -199,7 +207,7 @@ func (svr *Server) HandlePut(w http.ResponseWriter, r *http.Request) (commitment
199207
if err != nil {
200208
err = fmt.Errorf("failed to decode commitment from key %v (commitment mode %v): %w", key, meta.Mode, err)
201209
svr.WriteBadRequest(w, err)
202-
return commitments.CommitmentMeta{}, err
210+
return meta, err
203211
}
204212
}
205213

@@ -214,7 +222,7 @@ func (svr *Server) HandlePut(w http.ResponseWriter, r *http.Request) (commitment
214222
if err != nil {
215223
err = fmt.Errorf("failed to encode commitment %v (commitment mode %v): %w", commitment, meta.Mode, err)
216224
svr.WriteInternalError(w, err)
217-
return commitments.CommitmentMeta{}, err
225+
return meta, err
218226
}
219227

220228
svr.log.Info(fmt.Sprintf("write commitment: %x\n", comm))

server/server_test.go

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ func TestGetHandler(t *testing.T) {
3131

3232
mockRouter := mocks.NewMockIRouter(ctrl)
3333

34-
server := NewServer("localhost", 8080, mockRouter, log.New(), metrics.NoopMetrics)
34+
m := metrics.NewMetrics("default")
35+
server := NewServer("localhost", 8080, mockRouter, log.New(), m)
3536

3637
tests := []struct {
3738
name string
@@ -84,7 +85,7 @@ func TestGetHandler(t *testing.T) {
8485
expectedCode: http.StatusInternalServerError,
8586
expectedBody: "",
8687
expectError: true,
87-
expectedCommitmentMeta: commitments.CommitmentMeta{},
88+
expectedCommitmentMeta: commitments.CommitmentMeta{Mode: commitments.OptimismGeneric, CertVersion: 0},
8889
},
8990
{
9091
name: "Success - OP Keccak256",
@@ -106,7 +107,7 @@ func TestGetHandler(t *testing.T) {
106107
expectedCode: http.StatusInternalServerError,
107108
expectedBody: "",
108109
expectError: true,
109-
expectedCommitmentMeta: commitments.CommitmentMeta{},
110+
expectedCommitmentMeta: commitments.CommitmentMeta{Mode: commitments.OptimismAltDA, CertVersion: 0},
110111
},
111112
{
112113
name: "Success - OP Alt-DA",
@@ -138,6 +139,20 @@ func TestGetHandler(t *testing.T) {
138139
require.Equal(t, tt.expectedCode, rec.Code)
139140
require.Equal(t, tt.expectedCommitmentMeta, meta)
140141
require.Equal(t, tt.expectedBody, rec.Body.String())
142+
143+
})
144+
}
145+
for _, tt := range tests {
146+
t.Run(tt.name+"/CheckMiddlewaresNoPanic", func(_ *testing.T) {
147+
tt.mockBehavior()
148+
149+
req := httptest.NewRequest(http.MethodGet, tt.url, nil)
150+
rec := httptest.NewRecorder()
151+
// we also run the request through the middlewares, to make sure no panic occurs
152+
// could happen if there's a problem with the metrics. For eg, in the past we saw
153+
// panic: inconsistent label cardinality: expected 3 label values but got 1 in []string{"GET"}
154+
handler := WithLogging(WithMetrics(server.HandleGet, server.m), server.log)
155+
handler(rec, req)
141156
})
142157
}
143158
}
@@ -266,4 +281,18 @@ func TestPutHandler(t *testing.T) {
266281
require.Equal(t, tt.expectedCommitmentMeta, meta)
267282
})
268283
}
284+
285+
for _, tt := range tests {
286+
t.Run(tt.name+"/CheckMiddlewaresNoPanic", func(_ *testing.T) {
287+
tt.mockBehavior()
288+
289+
req := httptest.NewRequest(http.MethodGet, tt.url, nil)
290+
rec := httptest.NewRecorder()
291+
// we also run the request through the middlewares, to make sure no panic occurs
292+
// could happen if there's a problem with the metrics. For eg, in the past we saw
293+
// panic: inconsistent label cardinality: expected 3 label values but got 1 in []string{"GET"}
294+
handler := WithLogging(WithMetrics(server.HandlePut, server.m), server.log)
295+
handler(rec, req)
296+
})
297+
}
269298
}

0 commit comments

Comments
 (0)