I got tired of paying $26/seat/month for error tracking on side projects, so I built FindBug - a Rails engine that captures exceptions and performance data with all the data living on your own infrastructure. Zero SaaS, full ownership, MIT-licensed.
π Website: findbug.dev
π Documentation: findbug.dev/docs
π RubyGems: rubygems.org/gems/findbug
β GitHub: github.com/ITSSOUMIT/findbug
The pain points that pushed me to build this
If you've run a Rails monolith with Sentry / Bugsnag / Rollbar, you've felt these:
- Cost scales with team size, not value delivered. A 5-person team is $130+/mo before catching a single bug.
- Data lives on someone else's servers - fine for most apps, awkward for anything with PII, GDPR, or SOC concerns.
- Network dependency - if their edge is having a bad day, you lose telemetry exactly when you need it most.
- Setup ritual - API keys, env-specific DSNs, separate dashboards to log into, SDK version drift.
What FindBug looks like
# Gemfile
gem "findbug", "~> 0.5.0"
$ bundle install
$ rails generate findbug:install
$ rails db:migrate
That's the entire install. After this:
- Unhandled exceptions in controllers and middleware are captured automatically
- HTTP performance + SQL queries + N+1 patterns are instrumented
- A dashboard is mounted at
/findbug - A background thread flushes data from Redis to your database every 30 seconds - no Sidekiq required
Architecture: never block the request
The non-negotiable design rule is that capturing an error must not slow down your users:
Request β Middleware catches exception β Scrub PII
β Push to Redis buffer (Thread.new, ~1β2ms)
β Background persister flushes Redis β DB every 30s in batches of 100
β Dashboard reads from DB on demand
-
Capture overhead: ~1β2ms - single
LPUSHon a dedicated Redis connection pool, fired viaThread.new - HTTP request blocking: 0ms - capture is fire-and-forget
- Circuit breaker: 5 consecutive Redis failures opens the breaker for 30s, so your app stays fast even if Redis is unreachable
- Dedicated connection pool: separate from your app's Redis/Sidekiq, so a spike in error volume can't starve your cache
Manual capture
When you want to swallow an exception but still track it:
begin
risky_operation
rescue => e
Findbug.capture_exception(e, user_id: current_user.id)
end
Or capture a non-exception event:
Findbug.capture_message("Rate limit exceeded", :warning, user_id: 123)
Track a custom block for performance:
Findbug.track_performance("external_api_call") do
ExternalAPI.fetch_data
end
Controller helpers
Attach request-scoped context that's included with every error captured during that request:
class ApplicationController < ActionController::Base
before_action :set_findbug_context
def set_findbug_context
findbug_set_user(current_user)
findbug_set_context(
plan: current_user&.plan,
organization_id: current_org&.id
)
end
end
Breadcrumbs work the way you'd expect:
findbug_breadcrumb("User clicked checkout", category: "ui")
findbug_breadcrumb("Payment API called", category: "http", data: { amount: 99.99 })
Database-agnostic (v0.5.0)
This was the biggest improvement in the latest release. The migrations and model layer detect your ActiveRecord::Base.connection.adapter_name at runtime and pick the right column types and SQL functions:
| Adapter | JSON column | Time bucketing SQL |
|---|---|---|
| PostgreSQL | jsonb |
date_trunc(...) |
| MySQL | json |
DATE_FORMAT(...) / DATE(...)
|
| SQLite |
text (with JSON serialisation) |
strftime(...) / DATE(...)
|
Application code is identical regardless of adapter - the JSON accessors always return native Ruby Hash / Array.
If you're writing your own migrations against the same multi-DB strategy, the helper is public API:
Findbug::AdapterHelper.json_column_type # :jsonb / :json / :text
Findbug::AdapterHelper.json_default({})
Findbug::AdapterHelper.date_trunc_sql("hour", "captured_at")
Alerts configured at runtime, not in code
Email / Slack / Discord / Webhook channels live in a DB table managed from the dashboard at /findbug/alerts. No redeploy to add a webhook. Same-error notifications are throttled by fingerprint (default 5-minute window).
Compared to existing solutions
| Sentry / Bugsnag | FindBug | |
|---|---|---|
| Cost | $26+ per seat / month | Free, MIT |
| Data location | Third-party servers | Your infra |
| Network dependency | Required | None |
| Setup | API keys + SDK + per-env config | One gem, one command |
| Alert config | Their dashboard | Your dashboard |
| Customisation | Bounded by their UI | Fork the gem |
| Job scheduler needed | No | No (built-in thread) |
Stack
- Ruby 3.1+ Β· Rails 7.0+ (7.x and 8.x both tested) Β· Redis 4.0+
- PostgreSQL / MySQL / SQLite - all supported, adapter auto-detected
- 79 RSpec examples covering adapter detection, JSON-column normalisation, model behaviour, and aggregation
What it doesn't do (yet)
Being honest about the gap:
- No source-map handling - server-side errors only for now
- No frontend JS error tracking - on the v0.6 roadmap for Rails apps that render views
- No multi-project support - one gem = one app
- No SaaS option - you self-host or you don't use it
Links
- π Website & docs: findbug.dev Β· findbug.dev/docs
- π RubyGems: rubygems.org/gems/findbug
- π» GitHub: github.com/ITSSOUMIT/findbug
If you find this useful, a β on GitHub means a lot - it helps other Rails developers find the gem:
Built by Soumit Das. Would love feedback - especially from anyone running it on MySQL (the new adapter-agnostic path is fresh) or anyone with thoughts on the frontend-error-tracking direction.
Top comments (0)