probe.Measure performs an HTTP GET and records total elapsed time from request start to body fully read. main.go prints URL, status code, and total for each positional URL argument, exiting 1 on any failure. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
57 lines
1.3 KiB
Go
57 lines
1.3 KiB
Go
// Package probe measures per-phase HTTP request latency.
|
|
package probe
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// Phase holds the measured duration of a single request phase.
|
|
type Phase struct {
|
|
Duration time.Duration
|
|
// Present is false when the phase was skipped (e.g. no TLS for http://).
|
|
Present bool
|
|
}
|
|
|
|
// Result holds all timing phases for a single HTTP request.
|
|
type Result struct {
|
|
URL string
|
|
DNS Phase
|
|
Connect Phase
|
|
TLS Phase
|
|
TTFB Phase // server processing: WroteRequest → GotFirstResponseByte
|
|
Transfer Phase // body read: GotFirstResponseByte → body closed
|
|
Total Phase
|
|
|
|
// StatusCode is the HTTP response status code (0 on error).
|
|
StatusCode int
|
|
// Err is non-nil if the request failed.
|
|
Err error
|
|
}
|
|
|
|
// Measure performs an HTTP GET to url and returns a Result.
|
|
// In Step 1 only the Total phase is populated.
|
|
func Measure(url string) Result {
|
|
r := Result{URL: url}
|
|
|
|
start := time.Now()
|
|
|
|
resp, err := http.Get(url) //nolint:noctx
|
|
if err != nil {
|
|
r.Err = err
|
|
r.Total = Phase{Duration: time.Since(start), Present: true}
|
|
return r
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
_, err = io.Copy(io.Discard, resp.Body)
|
|
|
|
r.Total = Phase{Duration: time.Since(start), Present: true}
|
|
r.StatusCode = resp.StatusCode
|
|
if err != nil {
|
|
r.Err = err
|
|
}
|
|
return r
|
|
}
|