Skip to content

Commit b31e04e

Browse files
authored
fix(otel): Map 500 errors to 503 (#13173)
1 parent 740551b commit b31e04e

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

pkg/distributor/http.go

+20-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,26 @@ func (d *Distributor) PushHandler(w http.ResponseWriter, r *http.Request) {
2323
}
2424

2525
func (d *Distributor) OTLPPushHandler(w http.ResponseWriter, r *http.Request) {
26-
d.pushHandler(w, r, push.ParseOTLPRequest)
26+
interceptor := newOtelErrorHeaderInterceptor(w)
27+
d.pushHandler(interceptor, r, push.ParseOTLPRequest)
28+
}
29+
30+
// otelErrorHeaderInterceptor maps 500 errors to 503.
31+
// According to the OTLP specification, 500 errors are never retried on the client side, but 503 are.
32+
type otelErrorHeaderInterceptor struct {
33+
http.ResponseWriter
34+
}
35+
36+
func newOtelErrorHeaderInterceptor(w http.ResponseWriter) *otelErrorHeaderInterceptor {
37+
return &otelErrorHeaderInterceptor{ResponseWriter: w}
38+
}
39+
40+
func (i *otelErrorHeaderInterceptor) WriteHeader(statusCode int) {
41+
if statusCode == http.StatusInternalServerError {
42+
statusCode = http.StatusServiceUnavailable
43+
}
44+
45+
i.ResponseWriter.WriteHeader(statusCode)
2746
}
2847

2948
func (d *Distributor) pushHandler(w http.ResponseWriter, r *http.Request, pushRequestParser push.RequestParser) {

pkg/distributor/http_test.go

+32
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,38 @@ func TestRequestParserWrapping(t *testing.T) {
8282
require.True(t, called)
8383
}
8484

85+
func Test_OtelErrorHeaderInterceptor(t *testing.T) {
86+
for _, tc := range []struct {
87+
name string
88+
inputCode int
89+
expectedCode int
90+
}{
91+
{
92+
name: "500",
93+
inputCode: http.StatusInternalServerError,
94+
expectedCode: http.StatusServiceUnavailable,
95+
},
96+
{
97+
name: "400",
98+
inputCode: http.StatusBadRequest,
99+
expectedCode: http.StatusBadRequest,
100+
},
101+
{
102+
name: "204",
103+
inputCode: http.StatusNoContent,
104+
expectedCode: http.StatusNoContent,
105+
},
106+
} {
107+
t.Run(tc.name, func(t *testing.T) {
108+
r := httptest.NewRecorder()
109+
i := newOtelErrorHeaderInterceptor(r)
110+
111+
http.Error(i, "error", tc.inputCode)
112+
require.Equal(t, tc.expectedCode, r.Code)
113+
})
114+
}
115+
}
116+
85117
func stubParser(_ string, _ *http.Request, _ push.TenantsRetention, _ push.Limits, _ push.UsageTracker) (*logproto.PushRequest, *push.Stats, error) {
86118
return &logproto.PushRequest{}, &push.Stats{}, nil
87119
}

0 commit comments

Comments
 (0)