How do I see production logs for a deployed Rails app?
Run kamal app logs --follow to stream, or kamal app logs --lines 200 --grep Error to search what already happened. Rails 8 logs one line per request in production, so the useful move is filtering by request id and following that one request through the job and mailer lines it produced.
The commands worth memorizing
bin/kamal app logs --follow
bin/kamal app logs --lines 500 --grep "Completed 500"
bin/kamal app logs --lines 500 --grep "<request-id>"
The third one is the one that turns a wall of text into a story. Every log line in production carries the request id, so grepping it gives you the request, the SQL it ran, the job it enqueued and the mail it sent, in order.
Find the request id from the outside
curl -sI https://yourdomain.com/up | grep -i x-request-id
Rails echoes the id in a response header, so a user who can reproduce a problem can hand you the id from their browser's network tab and you can pull exactly their request.
Logs are not a monitoring system
Container logs rotate and are lost when the container is replaced, which happens on every deploy.
For anything you need after the fact, send it somewhere durable. One Shot has an error reporter seam
at app/adapters/error_reporter.rb that follows the same adapter and fake pattern as the rest of the
kit: it no-ops without credentials and reports to a real service with them. That is where an
exception tracker plugs in, not into a log grep.
Turn down the noise before you need it
Production defaults to :info, which includes every request. The level is set in
config/environments/production.rb. If the log is unreadable, that is usually assets or health
checks rather than your app. The health check route is declared at the top of config/routes.rb and
is hit every few seconds by design, so filtering it out is the first thing worth doing:
bin/kamal app logs --lines 500 | grep -v "/up"
When the container will not start at all
kamal app logs reads a running container. If the deploy failed on the health check, the container
already exited, and the same command still shows its final output. That is where the boot error is,
and it is almost always a secret that did not arrive. See
First Deploy Checklist.