# latprobe — Website Latency Probe A command-line tool that measures the latency of one or more websites, with a **full per-request phase breakdown** — DNS resolution, TCP connect, TLS handshake, server processing (time-to-first-byte), and content transfer. Not just a ping: `latprobe` shows you _where_ the time goes. ## Why A single total request time hides the root cause of slowness. Is it DNS? A slow TLS negotiation? A laggy server? `latprobe` breaks the request into its constituent phases so the bottleneck is immediately obvious. ## Implementations | Language | Status | Location | |----------|-----------|------------| | Go | In progress | `go/` | | Python | Planned | `python/` | Both implementations produce identical CLI behaviour and output formats. --- ## Usage (Go) ``` latprobe [flags] [url ...] Flags: -n, --count int Number of requests per URL (default 1) --json Output results as JSON instead of text Examples: latprobe https://example.com latprobe -n 5 https://example.com https://www.google.com latprobe --json https://example.com | jq . ``` --- ## Output ### Text (default) ``` https://example.com DNS lookup : 12.34 ms TCP connect : 8.91 ms TLS handshake : 45.20 ms Server (TTFB) : 78.56 ms Transfer : 2.10 ms ───────────────────────── Total : 147.11 ms ``` With `-n 5` (min / avg / max columns): ``` https://example.com (5 samples) min avg max DNS lookup : 10.1ms 12.3ms 15.7ms TCP connect : 7.8ms 9.0ms 11.2ms ... ``` ### JSON (`--json`) ```json { "url": "https://example.com", "samples": 1, "phases": { "dns": { "ms": 12.34 }, "connect": { "ms": 8.91 }, "tls": { "ms": 45.20 }, "ttfb": { "ms": 78.56 }, "transfer": { "ms": 2.10 }, "total": { "ms": 147.11 } } } ``` --- ## Implementation Roadmap ### Go | Step | Feature | Status | |------|---------|--------| | 0 | Project scaffold — directory structure, `go.mod`, minimal binary | ✅ Done | | 1 | Simple total latency — single URL, wall-clock time | ✅ Done | | 2 | Per-phase breakdown — DNS, TCP, TLS, TTFB, transfer (`net/http/httptrace`) | ✅ Done | | 3 | Multiple URLs + `--count`/`-n` — min/avg/max aggregates | ✅ Done | | 4 | `--json` output flag | ✅ Done | | 5 | Failure handling — `--timeout`, `--fail`, distinct exit codes, partial timing | ✅ Done | | 6 | Integration tests — in-process matrix + subprocess smoke tests | ✅ Done | ### Python Begins after the Go implementation is approved. Will mirror the same CLI and output format. Timed using low-level socket hooks (DNS via `socket.getaddrinfo`, connection timings via custom socket wrap or `httpx`/`urllib3` hooks). --- ## Development Environment - Go 1.26.4 / darwin arm64 - Python 3.14.6 - No external dependencies (Go uses stdlib only; Python TBD at port time) ## Project Conventions See [CLAUDE.md](CLAUDE.md) for the development conventions followed in this project: - Plans saved to `docs/plans/` with timestamped filenames - Completed features logged in `CHANGELOG.md` with timestamps - Per-feature user docs in `docs/usage/`