DEV Community

Aditya Pandit
Aditya Pandit

Posted on • Edited on

ErrorTrack: Self-hosted Sentry-style error tracking for Rails, in your own database

Sentry and Honeybadger are great — until you don't want another vendor, another bill, or exception data leaving your infrastructure.

ErrorTrack is a small Rails engine that:

  • Captures unhandled exceptions (Rack middleware) and Rails.error reports
  • Groups repeats into issues (count, first/last seen)
  • Stores backtrace + request context in your DB
  • Serves a dashboard at /errors — vanilla JS, no Hotwire/React/npm/CDN

Works the same in full-stack Rails and rails new --api apps.


Why it helps

Pain What ErrorTrack does
Paid error services Free, MIT, self-hosted
Data residency / privacy Errors stay in your DB
API-only / Next.js backends /errors still works on the Rails host
Ops complexity One gem + one migration

Install

Add to your Gemfile:

gem "error_track", "~> 0.1.0"
Enter fullscreen mode Exit fullscreen mode

Then run:

bundle install
rails generate error_track:install
rails db:migrate
Enter fullscreen mode Exit fullscreen mode

That adds the migration, initializer, and mounts the engine at /errors. Open /errors in your app.


Manual reporting

begin
  risky_call
rescue => e
  ErrorTrack.notify(e, context: { user_id: current_user&.id, order_id: order.id })
  raise
end
Enter fullscreen mode Exit fullscreen mode

Secure the dashboard

/errors has no auth by default. Lock it down:

# config/initializers/error_track.rb
Rails.application.config.to_prepare do
  ErrorTrack::ErrorsController.class_eval do
    before_action :authenticate_admin!
  end
end
Enter fullscreen mode Exit fullscreen mode

Or with Devise:

authenticate :user, ->(u) { u.admin? } do
  mount ErrorTrack::Engine => "/errors"
end
Enter fullscreen mode Exit fullscreen mode

HTTP Basic works well for API-only apps:

Rails.application.config.to_prepare do
  ErrorTrack::ErrorsController.class_eval do
    http_basic_authenticate_with(
      name: Rails.application.credentials.dig(:error_track, :user),
      password: Rails.application.credentials.dig(:error_track, :password)
    )
  end
end
Enter fullscreen mode Exit fullscreen mode

How grouping works

Fingerprint = exception class + first in-app backtrace line (line numbers normalized). Same bug 500 times → one row with count 500.


Links

Feedback, issues, and PRs welcome. If this saves you a Sentry invoice — star the repo and tell me what you'd add next.

Top comments (0)