Seeing the Request
Grove is the web server, so it sees every request before your application does and after it finishes. This chapter is about what that makes possible, and it is the feature you will miss most if you ever go back.
The problem
Something went wrong in a request you were not watching. A webhook arrived at three in the morning. A form submission failed for one user. An AJAX call returned 500 and the page swallowed it. In each case the request is gone: you have a log line if you are lucky, and the rest is reconstruction from memory and guesswork.
Worse, reproducing it means recreating the exact request — the same headers, the same body, the same session — which for anything involving a third party is an afternoon of work before you have even started debugging.
The hard way
The usual tools each see one slice. Your framework's debug bar sees requests that rendered a page — not the API call, not the webhook, not the one that died before the view. The access log sees a line with a status code and no body. Xdebug sees everything but only while you sit there with a breakpoint, which is no use for something that happened at three in the morning.
None of them can replay. And none of them can see the whole request, because none of them is the web server.
The timeline
grove requests
grove requests --site freddy
Every request Grove served: method, path, status, duration. Not a sample, not only the ones that rendered, not only the ones your framework knew about — every one, because Grove handled it.
Open one and you get its detail: headers, body, response, timing. The request that failed at three in the morning is there, with the payload that caused it.
Replay, and copy as
This is the part that changes how you debug. A captured request can be replayed — sent again, exactly as it arrived — so the loop becomes: replay, read the error, change the code, replay. Seconds per iteration, with no third party involved and no form to fill in again.
And it can be copied out:
- as curl — to paste into a terminal, or to a colleague who does not have your machine.
- as an HTTP file — for the client in your editor.
- as a Pest test — and this is the one to notice. A bug you just reproduced becomes a failing test in one click, which is the difference between fixing a bug and fixing it permanently. The barrier to writing that test was never the typing; it was reconstructing the request.
The queries a request caused
With SQL capture on, the timeline shows the database queries belonging to each request — not a global query log you must correlate by timestamp, but the queries that request caused, in order, with their durations.
Which makes the N+1 problem visible rather than deducible. A page that runs 340 queries where you expected six is obvious in a list; it is nearly invisible in a page that renders in 900ms on a laptop with a warm local database, right up until it is a production incident on a table with a million rows.
grove explain
walks the causal chain for a request in one place: what arrived, what ran, what it asked the database, what came back. The value is that it is one place. Every part of that story exists somewhere in a conventional setup, in four different tools with four different clocks.
What you learned
- Grove sees every request — including the ones that died before your framework was involved.
- Replay turns debugging into a loop measured in seconds, with no third party and no form to refill.
- Copy as Pest makes the fix permanent. The barrier to that test was reconstructing the request, not typing it.
- Queries are attributed to the request that caused them, which makes N+1 visible instead of deducible.
- Leave capture on. The request you wish you had is always one that already happened.