Dontbugme

A flight recorder for Rails applications. Reconstruct the full execution story of Sidekiq jobs and HTTP requests — see exactly what database queries ran, what HTTP services were called, what exceptions were raised, with source locations pointing to your code.

Quick Start

Get up and running in under 2 minutes:

1. Add the gem and install

# Gemfile
gem 'dontbugme'
bundle install

2. Run the installer (creates config and mounts the Web UI)

rails g dontbugme:install

This adds config/initializers/dontbugme.rb and mounts the engine at /inspector in your routes.

3. Start your app and generate traffic

rails s          # Start the server
# In another terminal, if you use Sidekiq:
bundle exec sidekiq

Make an HTTP request (visit a page, hit an API) or run a Sidekiq job. Dontbugme records automatically in development.

4. View traces

Option A — Web UI (easiest): Open http://localhost:3000/inspector in your browser. Browse, search, and compare traces.

Option B — CLI: From your Rails app root (so it finds the SQLite DB):

bundle exec dontbugme list                    # List recent traces
bundle exec dontbugme show <trace_id>         # Show a trace
bundle exec dontbugme search --status=error   # Find failed traces

That's it. No database migrations needed — SQLite is used by default in development (tmp/inspector/inspector.db).


Installation

Add to your Gemfile:

gem 'dontbugme'

Then run:

bundle install
rails g dontbugme:install

Usage

Automatic Recording

Dontbugme automatically records:

  • Sidekiq jobs — via Sidekiq server middleware
  • HTTP requests — via Rack middleware
  • SQL queries — via ActiveSupport::Notifications
  • HTTP calls — Net::HTTP (including Faraday, which uses it)
  • Redis — Redis gem operations
  • Cache — Rails cache read/write/delete
  • Mailer — ActionMailer deliveries
  • Job enqueue — Active Job enqueues

In development, recording is on by default. Run your app normally, then inspect:

# List recent traces
bundle exec dontbugme list

# Show a specific trace
bundle exec dontbugme show tr_abc123

# Filter spans
bundle exec dontbugme show tr_abc123 --only=sql
bundle exec dontbugme show tr_abc123 --slow=10

# JSON output
bundle exec dontbugme show tr_abc123 --json

Manual Tracing

Wrap any block to capture a trace:

trace = Dontbugme.trace("my debug session") do
  User.find(42)
  Order.where(user_id: 42).count
end

puts trace.to_timeline
# Or: trace.spans, trace.status, trace.duration_ms

Manual Spans and Snapshots

Add custom spans and snapshots within a trace. Spans capture the return value by default so you can see outputs in the UI:

trace = Dontbugme.trace("checkout flow") do
  Dontbugme.span("Calculate tax") do
    tax = order.calculate_tax  # output shown in UI
  end
  Dontbugme.snapshot(user: user.attributes.slice("id", "email"), total: order.total)
  Dontbugme.tag(customer_tier: "enterprise")
end

Use capture_output: false to skip capturing the return value for sensitive data.

Automatic Variable Tracking

Dontbugme automatically captures local variable changes between lines in your app code. No manual instrumentation needed — when a variable like token changes from abc123 to abc124, you'll see an observe span with Input and Output in the UI.

token = Member.find(1).confirmation_token
token += 1
Member.find(1).update(confirmation_token: token)

The UI will show both Input and Output for the transformation. Enabled by default in development; disable with config.capture_variable_changes = false. Only tracks simple types (String, Integer, Float, etc.) to avoid noise.

Manual Observe (optional)

For explicit control, use Dontbugme.observe:

token = Dontbugme.observe('token increment', token) { token + 1 }

Span Categories

Access spans by category for assertions or analysis:

trace.spans.sql        # SQL queries
trace.spans.http       # HTTP calls
trace.spans.redis      # Redis operations
trace.spans.category(:mailer)  # Any category
bundle exec dontbugme search --status=error --class=SendInvoiceJob --limit=10

Trace Diff

Compare two executions to see what changed:

bundle exec dontbugme diff tr_success tr_failed

Shows IDENTICAL, CHANGED, MISSING, and NEW spans between the two traces.

Correlation Chain

When a request enqueues jobs, they share a correlation_id. Follow the full chain:

bundle exec dontbugme trace tr_request_id --follow

Shows all traces (request + enqueued jobs) with the same correlation ID. Correlation IDs are automatically propagated from HTTP requests to Sidekiq jobs (and from job to child job) when using the Rails integration.

Web UI

A lightweight web interface to browse traces. The installer mounts it at /inspector. It's enabled by default in development and disabled in production.

Visit /inspector to browse traces, search, and compare. Tweak in config/initializers/dontbugme.rb:

config.enable_web_ui = true
config.web_ui_mount_path = '/inspector'

Configuration

Edit config/initializers/dontbugme.rb (created by the installer):

Dontbugme.configure do |config|
  config.store = :sqlite
  config.sqlite_path = "tmp/inspector/inspector.db"
  config.recording_mode = :always
  config.capture_sql_binds = true
  config.source_mode = :full

  # Capture outputs for debugging (development only)
  config.capture_span_output = true      # return values from Dontbugme.span
  config.capture_http_body = true       # HTTP response bodies
  config.capture_redis_return_values = true  # Redis command return values
end

Storage

  • SQLite (default): Zero config. Data at tmp/inspector/inspector.db
  • PostgreSQL: Uses your Rails DB. Set config.store = :postgresql
  • Memory: For tests. Traces lost on process exit.

Production

In production, Dontbugme uses safer defaults: PostgreSQL storage, async writes, selective recording, and the Web UI disabled. No extra setup is required if you use PostgreSQL — the gem creates the dontbugme_traces table automatically.

Default production behavior

  • Store: PostgreSQL (uses your Rails DB connection)
  • Web UI: Disabled — enable only if you add authentication
  • Recording: Selective — always records failures (record_on_error), samples successful traces
  • Async writes: Enabled to avoid blocking requests/jobs
# config/initializers/dontbugme.rb
Dontbugme.configure do |config|
  config.store = :postgresql
  config.async_store = true

  # Sample 5% of successful traces to limit storage
  config.recording_mode = :selective
  config.sample_rate = 0.05
  config.record_on_error = true   # Always capture failures

  # Optional: record only specific jobs
  # config.record_jobs = %w[SendInvoiceJob ProcessPaymentJob]
  # config.record_requests = :all  # or a proc for custom logic
end

Enabling the Web UI in production

If you need the Web UI in production (e.g. for on-call debugging), protect it with authentication:

# config/initializers/dontbugme.rb
Dontbugme.configure do |config|
  config.enable_web_ui = true
  config.web_ui_mount_path = '/inspector'
end

Then add authentication in your routes (e.g. with Devise, authenticate before the mount, or HTTP basic auth via a constraint).

Cleanup and retention

Production defaults to 24-hour retention. Schedule cleanup to enforce it:

# config/schedule.rb (whenever) or a Sidekiq cron job
Dontbugme::CleanupJob.perform

Example with Sidekiq:

# app/jobs/dontbugme_cleanup_job.rb
class DontbugmeCleanupJob < ApplicationJob
  queue_as :low

  def perform
    Dontbugme::CleanupJob.perform
  end
end
# Schedule daily via sidekiq-cron, whenever, or similar

CLI in production

Run the CLI from your production app directory (or a deploy host with DB access). It uses your Rails DB config:

RAILS_ENV=production bundle exec dontbugme list
RAILS_ENV=production bundle exec dontbugme search --status=error --limit=50

Cleanup

Traces are ephemeral. Run Dontbugme::CleanupJob.perform to enforce retention. See Production for scheduling via Sidekiq or cron.

Requirements

  • Ruby >= 3.0
  • Rails >= 7.0 (for full integration)
  • Sidekiq >= 7.0 (optional, for job tracing)

License

MIT