Proposal Details
Background
The net/http/httptrace package provides hooks to trace the lifecycle of HTTP client requests.
For example:
GotConn marks when a connection is acquired.
GotFirstResponseByte marks when the first response byte is received.
However, there is currently no hook that signals when the response body has been fully read and closed.
Prior art / Ecosystem evidence
Today there is no convenient mechanism in Go’s httptrace.ClientTrace to measure when the response body has been fully read.
- OpenTelemetry Go currently uses the PutIdleConn hook as a workaround to approximate "response end." This is fragile: PutIdleConn is never called for HTTP/2 (and HTTP/3), which has already led to user-reported issues where client spans are never finished.
- Other instrumentation libraries either do not provide a way to capture “response fully read,” or require wrapping resp.Body manually at application level, which is inconsistent and error-prone.
- In general, PutIdleConn is not a suitable signal: by definition it is tied to connection pooling semantics and not to the actual lifecycle of the response. The Go documentation explicitly notes that this hook is not used for HTTP/2.
This leaves a clear gap for anyone building tracing or APM instrumentation in Go: there is no reliable, protocol-agnostic hook to signal that the response body is complete.
Proposal
Extend net/http/httptrace.ClientTrace with a new optional hook that signals when the response body has been fully consumed.
// GotResponseEnd is called once a response body has been fully read
// (EOF reached) or closed due to an error. The error is nil on normal completion.
GotResponseEnd func(err error)
Semantics
- Invocation:
- Called exactly once per request.
- Triggered when
resp.Body.Read returns io.EOF or a non-nil error, or when the body is explicitly closed early.
- Error reporting:
- If the body is read to completion,
err == nil.
- If the body ends prematurely (network error, context cancellation, explicit close), err contains the reason.
- Protocol coverage:
- Works uniformly for HTTP/1.x, HTTP/2, and future transports (e.g. HTTP/3).
- Relation to existing hooks:
- Complements
GotFirstResponseByte. Together they define clear start-and-end markers for response timing.
- Unlike
PutIdleConn, this hook is not tied to connection reuse and will always fire regardless of protocol.
Proposal Details
Background
The
net/http/httptracepackage provides hooks to trace the lifecycle of HTTP client requests.For example:
GotConnmarks when a connection is acquired.GotFirstResponseBytemarks when the first response byte is received.However, there is currently no hook that signals when the response body has been fully read and closed.
Prior art / Ecosystem evidence
Today there is no convenient mechanism in Go’s httptrace.ClientTrace to measure when the response body has been fully read.
This leaves a clear gap for anyone building tracing or APM instrumentation in Go: there is no reliable, protocol-agnostic hook to signal that the response body is complete.
Proposal
Extend
net/http/httptrace.ClientTracewith a new optional hook that signals when the response body has been fully consumed.Semantics
resp.Body.Readreturnsio.EOFor a non-nil error, or when the body is explicitly closed early.err == nil.GotFirstResponseByte. Together they define clear start-and-end markers for response timing.PutIdleConn, this hook is not tied to connection reuse and will always fire regardless of protocol.