Files
http-latency-prober/go/main.go
Jan Novak 0ecfb9bb1a feat(go): step 2 — per-phase request breakdown via httptrace
Instruments HTTP requests with net/http/httptrace.ClientTrace to capture
timestamps for DNS, TCP connect, TLS handshake, TTFB, and body transfer.
TLS row is omitted automatically for plain http:// URLs. Output is an
aligned text table with a separator before the Total row.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-01 00:23:36 +02:00

92 lines
1.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"flag"
"fmt"
"os"
"strings"
"latprobe/internal/probe"
)
const usageText = `latprobe — measure per-phase HTTP request latency
Usage:
latprobe [flags] <url> [url ...]
Flags:
-n, --count int Number of requests per URL (default 1)
--json Output results as JSON instead of text
-h, --help Show this help
Examples:
latprobe https://example.com
latprobe -n 5 https://example.com https://www.google.com
latprobe --json https://example.com | jq .
`
func main() {
count := flag.Int("count", 1, "number of requests per URL")
flag.IntVar(count, "n", 1, "number of requests per URL (shorthand)")
jsonOut := flag.Bool("json", false, "output results as JSON")
flag.Usage = func() { fmt.Fprint(os.Stderr, usageText) }
flag.Parse()
urls := flag.Args()
if len(urls) == 0 {
fmt.Fprint(os.Stderr, usageText)
os.Exit(1)
}
// --json and -n are parsed but not yet functional (wired in Steps 34).
_ = jsonOut
_ = count
failed := false
for i, url := range urls {
if i > 0 {
fmt.Println()
}
r := probe.Measure(url)
if r.Err != nil {
fmt.Fprintf(os.Stderr, "error %s: %v\n", r.URL, r.Err)
failed = true
continue
}
printResult(r)
}
if failed {
os.Exit(1)
}
}
func printResult(r probe.Result) {
fmt.Printf("%s (%d)\n", r.URL, r.StatusCode)
phases := []struct {
label string
p probe.Phase
}{
{"DNS lookup ", r.DNS},
{"TCP connect ", r.Connect},
{"TLS handshake ", r.TLS},
{"Server (TTFB) ", r.TTFB},
{"Transfer ", r.Transfer},
}
for _, ph := range phases {
if ph.p.Present {
fmt.Printf(" %s : %8.2f ms\n", ph.label, msec(ph.p))
}
}
fmt.Println(" " + strings.Repeat("─", 29))
fmt.Printf(" %s : %8.2f ms\n", "Total ", msec(r.Total))
}
func msec(p probe.Phase) float64 {
return float64(p.Duration.Microseconds()) / 1000
}