Files
http-latency-prober/docs/plans/2026-07-01-00-08-go-latency-tool.md
Jan Novak 5717f018b7 chore: initial scaffold for latprobe CLI tool
Sets up project structure, working conventions (CLAUDE.md), README with
the full assignment and roadmap, seeded CHANGELOG, and a buildable Go
scaffold (Step 0) with flag parsing and stub probe types.

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

5.5 KiB

Plan: Website latency CLI tool (Go first, then Python)

Context

We're building a small CLI tool that measures the latency of one or more websites given their URLs. The point of difference from a naive timer is a full per-phase breakdown of an HTTP request — DNS resolution, TCP connect, TLS handshake, server processing (time-to-first-byte), and content transfer — not just a single total number.

We start simple (total latency only) and grow the tool in clear steps. The Go implementation comes first; once the user is satisfied, we port the same behaviour to Python. This plan also establishes project-wide working conventions (plans, changelog, per-feature docs) up front.

Design decisions confirmed with the user:

  • Output: human-readable text by default, with a --json flag for machine output.
  • Sampling: a --count/-n flag repeats N requests per URL and reports min/avg/max per phase.
  • Input: accept multiple URLs as positional arguments, measured in turn.

Toolchain present: Go 1.26.4, Python 3.14.6.

Proposed layout

tt-excercise/
├── CLAUDE.md                 # working conventions (created first)
├── README.md                 # the assignment + implementation steps
├── CHANGELOG.md              # timestamped completed features
├── docs/
│   ├── plans/                # timestamped plans (this plan copied here)
│   └── usage/                # per-feature user documentation
├── go/
│   ├── go.mod                # module: latprobe (name adjustable)
│   ├── main.go               # CLI: flag parsing, orchestration, output
│   └── internal/probe/
│       └── probe.go          # timing logic via net/http/httptrace
└── python/                   # added later, during the port

Binary/module name proposed: latprobe (easy to change).

Foundation files (created at the start)

CLAUDE.md — working conventions

  • Every plan is saved under docs/plans/ with a filename starting with the current timestamp in yyyy-mm-dd-hh-mm format (e.g. 2026-07-01-00-08-go-latency-tool.md).
  • Every completed feature is appended to CHANGELOG.md with a timestamp.
  • Every feature ships with user documentation under docs/usage/ including a concrete example of how to use it.

README.md — the assignment

  • Project purpose: CLI tool to measure website latency, with a full per-request phase breakdown including DNS resolution.
  • Two implementations: Go first, then a Python port.
  • Usage sketch and the staged implementation roadmap (below).
  • Note that Go 1.26 / Python 3.14 are the development versions.

CHANGELOG.md

  • Seeded with a header; entries appended per completed feature.

Implementation steps (Go)

Each step is a self-contained, reviewable increment. We pause for the user's sign-off between steps. On completion of each: append to CHANGELOG.md and add its docs/usage/ page.

Step 0 — Scaffold. Create go/go.mod (go mod init latprobe), a minimal main.go that prints usage, and the directory structure. Confirms the toolchain builds.

Step 1 — Simple total latency. Accept a single URL argument, perform an HTTP GET, and print the total wall-clock time of the request. No breakdown yet. Reuse the standard library only (net/http, time).

Step 2 — Full per-phase breakdown (the core feature). Instrument the request with net/http/httptrace.ClientTrace to capture timestamps and derive each phase:

  • DNS lookup (DNSStartDNSDone)
  • TCP connect (ConnectStartConnectDone)
  • TLS handshake (TLSHandshakeStartTLSHandshakeDone, HTTPS only)
  • Server processing / TTFB (WroteRequestGotFirstResponseByte)
  • Content transfer (GotFirstResponseByte → response body fully read)
  • Total Print an aligned text breakdown. httptrace is the key reusable stdlib piece — no third-party dependency needed.

Step 3 — Multiple URLs + sampling. Accept multiple positional URLs; add --count/-n (default 1) to repeat each URL N times and report min/avg/max per phase. Group output clearly per URL.

Step 4 — JSON output. Add a --json flag producing structured output (per URL, per phase, with the min/avg/max aggregates and sample count). Keep the human-readable text as the default.

Reasonable extras to consider later (not committed now): --timeout, --method, redirect handling, HTTP/2 vs HTTP/1.1 reporting, exit codes on failure.

Port to Python (after Go is approved)

Mirror the same CLI and output. Python has no direct httptrace equivalent, so the plan will measure phases at a lower level — e.g. custom timing around socket.getaddrinfo (DNS), connection establishment, and TLS wrap, or by using urllib3/httpx connection hooks. The detailed Python design will be drafted as its own plan (saved to docs/plans/) when we reach that stage.

Verification

  • cd go && go build ./... succeeds at every step.
  • Manual runs against known hosts, e.g.:
    • ./latprobe https://example.com → total only (Step 1), full breakdown (Step 2+).
    • ./latprobe -n 5 https://example.com https://www.google.com → min/avg/max per URL.
    • ./latprobe --json https://example.com → valid JSON (pipe through a JSON validator).
  • Sanity-check phase numbers: phases should roughly sum to the total; HTTPS shows a TLS phase, plain HTTP does not.
  • go vet ./... clean.

Bookkeeping at execution time

On exiting plan mode, before/with Step 0:

  1. Copy this plan to docs/plans/2026-07-01-00-08-go-latency-tool.md.
  2. Create CLAUDE.md, README.md, CHANGELOG.md as described above.