Skip to content

Commit 98e82cc

Browse files
committed
otelhttp: Ignore informational response status codes when persisting status
Signed-off-by: Janusz Marcinkiewicz <[email protected]>
1 parent 3ea6585 commit 98e82cc

File tree

7 files changed

+61
-3
lines changed

7 files changed

+61
-3
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1111
### Changed
1212

1313
- Jaeger remote sampler's probabilistic strategy now uses the same sampling algorithm as `trace.TraceIDRatioBased` in `go.opentelemetry.io/contrib/samplers/jaegerremote`. (#6892)
14+
- Ignore informational response status codes (`100-199`) when storing the HTTP status code in `go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp` and `go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux`. (#6913)
1415

1516
### Removed
1617

instrumentation/github.com/gorilla/mux/otelmux/internal/request/resp_writer_wrapper.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func (w *RespWriterWrapper) Write(p []byte) (int, error) {
6161

6262
// WriteHeader persists initial statusCode for span attribution.
6363
// All calls to WriteHeader will be propagated to the underlying ResponseWriter
64-
// and will persist the statusCode from the first call.
64+
// and will persist the statusCode from the first call (except for informational response status codes).
6565
// Blocking consecutive calls to WriteHeader alters expected behavior and will
6666
// remove warning logs from net/http where developers will notice incorrect handler implementations.
6767
func (w *RespWriterWrapper) WriteHeader(statusCode int) {
@@ -77,6 +77,13 @@ func (w *RespWriterWrapper) WriteHeader(statusCode int) {
7777
// parent method.
7878
func (w *RespWriterWrapper) writeHeader(statusCode int) {
7979
if !w.wroteHeader {
80+
// Ignore informational response status codes.
81+
// Based on https://github.com/golang/go/blob/go1.24.1/src/net/http/server.go#L1216
82+
if statusCode >= 100 && statusCode <= 199 && statusCode != http.StatusSwitchingProtocols {
83+
w.ResponseWriter.WriteHeader(statusCode)
84+
return
85+
}
86+
8087
w.wroteHeader = true
8188
w.statusCode = statusCode
8289
}

instrumentation/github.com/gorilla/mux/otelmux/internal/request/resp_writer_wrapper_test.go

+12
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ func TestRespWriterWriteHeader(t *testing.T) {
2525
assert.Equal(t, http.StatusTeapot, rw.statusCode)
2626
}
2727

28+
func TestRespWriterWriteInformationalStatusCode(t *testing.T) {
29+
rw := NewRespWriterWrapper(&httptest.ResponseRecorder{}, func(int64) {})
30+
31+
rw.WriteHeader(http.StatusContinue)
32+
assert.Equal(t, http.StatusOK, rw.statusCode)
33+
assert.False(t, rw.wroteHeader)
34+
35+
rw.WriteHeader(http.StatusGone)
36+
assert.Equal(t, http.StatusGone, rw.statusCode)
37+
assert.True(t, rw.wroteHeader)
38+
}
39+
2840
func TestRespWriterFlush(t *testing.T) {
2941
rw := NewRespWriterWrapper(&httptest.ResponseRecorder{}, func(int64) {})
3042

instrumentation/net/http/otelhttp/internal/request/resp_writer_wrapper.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func (w *RespWriterWrapper) Write(p []byte) (int, error) {
6161

6262
// WriteHeader persists initial statusCode for span attribution.
6363
// All calls to WriteHeader will be propagated to the underlying ResponseWriter
64-
// and will persist the statusCode from the first call.
64+
// and will persist the statusCode from the first call (except for informational response status codes).
6565
// Blocking consecutive calls to WriteHeader alters expected behavior and will
6666
// remove warning logs from net/http where developers will notice incorrect handler implementations.
6767
func (w *RespWriterWrapper) WriteHeader(statusCode int) {
@@ -77,6 +77,13 @@ func (w *RespWriterWrapper) WriteHeader(statusCode int) {
7777
// parent method.
7878
func (w *RespWriterWrapper) writeHeader(statusCode int) {
7979
if !w.wroteHeader {
80+
// Ignore informational response status codes.
81+
// Based on https://github.com/golang/go/blob/go1.24.1/src/net/http/server.go#L1216
82+
if statusCode >= 100 && statusCode <= 199 && statusCode != http.StatusSwitchingProtocols {
83+
w.ResponseWriter.WriteHeader(statusCode)
84+
return
85+
}
86+
8087
w.wroteHeader = true
8188
w.statusCode = statusCode
8289
}

instrumentation/net/http/otelhttp/internal/request/resp_writer_wrapper_test.go

+12
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ func TestRespWriterWriteHeader(t *testing.T) {
2525
assert.Equal(t, http.StatusTeapot, rw.statusCode)
2626
}
2727

28+
func TestRespWriterWriteInformationalStatusCode(t *testing.T) {
29+
rw := NewRespWriterWrapper(&httptest.ResponseRecorder{}, func(int64) {})
30+
31+
rw.WriteHeader(http.StatusContinue)
32+
assert.Equal(t, http.StatusOK, rw.statusCode)
33+
assert.False(t, rw.wroteHeader)
34+
35+
rw.WriteHeader(http.StatusGone)
36+
assert.Equal(t, http.StatusGone, rw.statusCode)
37+
assert.True(t, rw.wroteHeader)
38+
}
39+
2840
func TestRespWriterFlush(t *testing.T) {
2941
rw := NewRespWriterWrapper(&httptest.ResponseRecorder{}, func(int64) {})
3042

internal/shared/request/resp_writer_wrapper.go.tmpl

+8-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func (w *RespWriterWrapper) Write(p []byte) (int, error) {
6161

6262
// WriteHeader persists initial statusCode for span attribution.
6363
// All calls to WriteHeader will be propagated to the underlying ResponseWriter
64-
// and will persist the statusCode from the first call.
64+
// and will persist the statusCode from the first call (except for informational response status codes).
6565
// Blocking consecutive calls to WriteHeader alters expected behavior and will
6666
// remove warning logs from net/http where developers will notice incorrect handler implementations.
6767
func (w *RespWriterWrapper) WriteHeader(statusCode int) {
@@ -77,6 +77,13 @@ func (w *RespWriterWrapper) WriteHeader(statusCode int) {
7777
// parent method.
7878
func (w *RespWriterWrapper) writeHeader(statusCode int) {
7979
if !w.wroteHeader {
80+
// Ignore informational response status codes.
81+
// Based on https://github.com/golang/go/blob/go1.24.1/src/net/http/server.go#L1216
82+
if statusCode >= 100 && statusCode <= 199 && statusCode != http.StatusSwitchingProtocols {
83+
w.ResponseWriter.WriteHeader(statusCode)
84+
return
85+
}
86+
8087
w.wroteHeader = true
8188
w.statusCode = statusCode
8289
}

internal/shared/request/resp_writer_wrapper_test.go.tmpl

+12
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ func TestRespWriterWriteHeader(t *testing.T) {
2525
assert.Equal(t, http.StatusTeapot, rw.statusCode)
2626
}
2727

28+
func TestRespWriterWriteInformationalStatusCode(t *testing.T) {
29+
rw := NewRespWriterWrapper(&httptest.ResponseRecorder{}, func(int64) {})
30+
31+
rw.WriteHeader(http.StatusContinue)
32+
assert.Equal(t, http.StatusOK, rw.statusCode)
33+
assert.False(t, rw.wroteHeader)
34+
35+
rw.WriteHeader(http.StatusGone)
36+
assert.Equal(t, http.StatusGone, rw.statusCode)
37+
assert.True(t, rw.wroteHeader)
38+
}
39+
2840
func TestRespWriterFlush(t *testing.T) {
2941
rw := NewRespWriterWrapper(&httptest.ResponseRecorder{}, func(int64) {})
3042

0 commit comments

Comments
 (0)