Nobody has started this yet — be first.
Business impact
Every minute spent by support or on-call trying to figure out which server-side log line matches this customer's complaint is a minute the customer is waiting for an answer, and a minute of engineering time spent on detective work instead of a fix. Without request-ID correlation, that matching is done by eyeballing timestamps and hoping nothing else happened in the same window -- it gets actively worse as traffic grows, right when you can least afford slow incident response. This is usually one of the first things a customer-facing API is missing before it's ready to handle real support load, and it directly affects how fast SLA-bound issues get resolved.
Problem
logRequests in internal/api/router.go logs method, path, status, and duration per request via log/slog. There is no way to correlate a single client-visible failure (say, a 429 a user reports) with the exact server log line for that request -- if two requests to the same path fail around the same time, the logs are indistinguishable, and the client has no token to hand back to support/on-call.
Current behavior
No response from the service carries any header a client can hand to support to identify their exact request, and the structured log line for a request has no field correlating it back to that request.
Expected behavior
Every response, success or failure, carries an X-Request-ID header: if the incoming request already has one, it is echoed back unchanged; if not, the server generates one. The structured log line for that request includes a request_id field with the same value, and the ID is available to any handler further down the chain via context.Context.
Steps to reproduce
curl -i localhost:8080/healthz | grep -i x-request-id // got: (nothing) // want: X-Request-ID: <some unique value>
Why this matters
This is the single most common "day one" observability gap in a service: without it, connecting a user's bug report to server-side logs means grepping by timestamp and hoping nothing else happened in that window.
Suggested approach
Add the ID-generation and header-echoing as its own middleware (a function with the same func(http.Handler) http.Handler shape as logRequests), so it composes the same way in Router(). Order matters: it needs to run before logRequests reads/sets anything it depends on, and before the mux dispatches to a real handler if you want handlers to be able to read it from r.Context(). Use an unexported context-key type (not a bare string) to avoid collisions with other packages' context values.
Acceptance criteria
Verification
go test ./test/ -run TestTask03 -v
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
Sign in to create it automatically, or do it yourself:
$git checkout -b feat/request-id-correlationFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin feat/request-id-correlationSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign inhttp://localhost:8080localhost:6380http://localhost:8081curl localhost:8080/healthz
curl localhost:8080/api/v1/rules
curl -s -X POST localhost:8080/api/v1/check -d '{"rule":"free-tier","key":"user-123"}' | jq
No Docker? STORE_BACKEND=memory is the default, so go run ./cmd/server alone (no Redis needed) exercises everything except the Redis-backed code paths.
Work the tickets in tasks/ (ordered easy → hard); each names one Go test in test/:
make test-race # go test -race -count=1 ./...
go test ./test/ -run TestTask01 -v # a single ticket
./test/run_all.sh # all 15, pass/fail summary
Level 2
Implement a feature
Extend the system within its own patterns.