llv

Rails has ~"beautiful"~ trashy noisy unreadable garbage logs that it vomits uselessly into your terminal. We can do better.

Local log viewer for Rails development.log. Tails the file, groups lines by request (or background job), and shows them in a master/detail view — browser by default, or a TUI.

This is vide-coded because solving this years-old frustration now only takes 30mins between other work. Feel free to enhance it.

Setup

In your Rails app, enable tagged-logging with the request id so HTTP lines can be grouped reliably. Edit config/environments/development.rb:

config.log_tags = [:request_id]

ActiveJob lines already carry their own tags, no change needed for those.

Install llv globally — it's a standalone CLI, not something you bundle into your app. Once published to RubyGems:

gem install llv

In the meantime, from a clone of this repo:

bundle install && rake install

Run

Browser UI (default):

llv path/to/development.log
# opens http://127.0.0.1:9292

Terminal UI:

llv --tui path/to/development.log

Useful flags:

  • --tail — only show lines appended after launch. By default llv replays the whole file first so you see existing requests too.
  • --limit N — keep at most N items in memory (default 500).
  • --port, --host — change the web server bind.
  • --no-open — don't auto-launch the browser.

TUI keys

I don't use many terminal apps so please contribute enhancements to make it behave more as you'd expect.

The TUI is a two-pane master/detail with one focused pane at a time. Cursor keys and the vi-style hjkl both work.

key when focus is LIST (left) when focus is DETAIL (right)
/ k previous request scroll one line up
/ j next request scroll one line down
/ l / enter move focus to DETAIL
/ h / esc move focus back to LIST
tab swap focus swap focus
PgUp / PgDn / space page through the list page through detail
Ctrl-U / Ctrl-D half-page up / down
g / Home first item scroll to top
G / End last item scroll to bottom
s toggle SQL source lines toggle SQL source lines
H / J / C toggle http / jobs / cable toggle http / jobs / cable
q / Ctrl-C quit quit

The header shows which pane has focus ([LIST] or [DETAIL]) and the divider thickens () when the detail pane is active.

What you see

  • Left pane — newest-first list of items. Each item is one HTTP request (with method, path, status, duration), one ActiveJob run, or one ActionCable (/cable) connection.
  • Right pane — the log lines that belong to the selected item, with the ANSI colours Rails already emits (bold cyan for SQL labels, bold blue for the SQL itself, etc.). SQL source lines are revealed alongside their query.

Filtering noise

ActionCable (/cable) requests are very chatty in development and are usually not what you're trying to debug. Each kind (http, jobs, cable) has its own independent toggle:

  • Browser: three buttons in the header — click one to toggle its requests on/off. They're independent, so "HTTP + Jobs but not Cable" is one click on the Cable button.
  • TUI: H toggles HTTP, J toggles Jobs, C toggles Cable. The header shows the current state and the total reflects items visible / items captured.

Layout

lib/llv/
  ansi.rb         # SGR <-> HTML span
  parser.rb       # line classifier, stateful for untagged-HTTP grouping
  group_store.rb  # thread-safe ring buffer, pub/sub
  tailer.rb       # listen-based file follower, rotation-aware
  web.rb          # Sinatra + SSE
  tui.rb          # bubbletea Model + lipgloss layout
  public/         # vanilla HTML/JS/CSS

Tests

bundle exec rake test
# or:
bundle exec ruby -Ilib -Itest test/parser_test.rb

Releasing to RubyGems

For maintainers. The Rakefile pulls in bundler/gem_tasks, which gives you rake build and rake release.

One-time setup — sign in to RubyGems so credentials land in ~/.gem/credentials:

gem signin

Cutting a new release:

  1. Bump Llv::VERSION in lib/llv/version.rb (llv.gemspec reads from there, so it's the single source of truth).
  2. Commit and push the version bump.
  3. bundle exec rake release — this builds pkg/llv-<version>.gem, tags v<version> in git, pushes the tag, then pushes the gem to rubygems.org.

If you want to do it by hand instead:

bundle exec rake build           # writes pkg/llv-<version>.gem
gem push pkg/llv-<version>.gem