bugwatch-ruby

Official Ruby/Rails SDK for BugWatch — open-source error monitoring.

Installation

# Gemfile
gem "bugwatch-ruby"
bundle install

Configuration

# config/initializers/bugwatch.rb
Bugwatch.configure do |c|
  c.api_key               = ENV["BUGWATCH_API_KEY"]
  c.endpoint              = ENV["BUGWATCH_ENDPOINT"]   # e.g. "https://your-app.herokuapp.com"
  c.release_stage         = Rails.env.to_s
  c.notify_release_stages = ["production", "staging"]
  c.ignore_classes        = ["ActionController::RoutingError"]
  c.app_version           = ENV["GIT_REV"]             # optional git SHA
end

User context

# app/controllers/application_controller.rb
before_action :set_bugwatch_user

private

def set_bugwatch_user
  return unless current_user
  Bugwatch.set_user(
    id:    current_user.id,
    email: current_user.email,
    name:  current_user.name
  )
end
Bugwatch.leave_breadcrumb("User clicked checkout", type: "ui", metadata: { cart_id: 42 })

Manual notification

begin
  risky_operation
rescue => e
  Bugwatch.notify(e)
  raise
end

Deploy tracking

Track deploys so BugWatch can correlate new errors with releases.

Bugwatch.track_deploy(
  version:     "abc1234",
  environment: "production",       # defaults to config.release_stage
  description: "Deployed abc1234",
  deployed_by: "ci"
)

Heroku

On Heroku, SOURCE_VERSION (the git SHA) is available during the build phase but not during the release phase. The recommended approach is to bake the SHA into a REVISION file at build time, then read it at release time.

1. Create a Rake task in lib/tasks/bugwatch.rake:

namespace :bugwatch do
  task write_revision: :environment do
    revision = ENV["SOURCE_VERSION"] || `git rev-parse HEAD 2>/dev/null`.strip
    if revision.present?
      File.write(Rails.root.join("REVISION"), revision)
      puts "Bugwatch: wrote REVISION #{revision[0..6]}"
    end
  end

  task track_deploy: :environment do
    revision_file = Rails.root.join("REVISION")
    version = ENV["SOURCE_VERSION"] \
      || (File.read(revision_file).strip if File.exist?(revision_file)).presence \
      || Time.now.utc.strftime("%Y%m%d%H%M%S")

    thread = Bugwatch.track_deploy(
      version: version,
      description: "Deployed #{version[0..6]}",
      deployed_by: ENV["BUGWATCH_DEPLOYED_BY"] || "heroku"
    )
    thread&.join(5)
    puts "Bugwatch: tracked deploy #{version[0..6]}"
  end
end

# Bake the SHA into the slug during assets:precompile
if Rake::Task.task_defined?("assets:precompile")
  Rake::Task["assets:precompile"].enhance(["bugwatch:write_revision"])
end

2. Add the deploy task to your Procfile release phase:

release: bundle exec rails db:migrate && bundle exec rails bugwatch:track_deploy

The build will write the commit SHA to REVISION, and the release phase will read it back and report the deploy to BugWatch.

User Feedback Widget

Drop a feedback form into any view so users can report issues directly from your app. The form submits to BugWatch's feedback API — no controller code needed.

<%%= bugwatch_feedback_widget %>

The helper renders a plain, unstyled HTML form with CSS classes you can target:

Class Element
.bugwatch-feedback-form The <form> wrapper
.bugwatch-feedback-field Each field's <div>
.bugwatch-feedback-label <label> elements
.bugwatch-feedback-input Text/email <input>
.bugwatch-feedback-textarea The message <textarea>
.bugwatch-feedback-submit Submit <button>
.bugwatch-feedback-success Success message (hidden by default)
.bugwatch-feedback-error Error message (hidden by default)

Options

<%%= bugwatch_feedback_widget(
  user_email: current_user&.email,
  user_name:  current_user&.name,
  placeholder: "Describe the issue...",
  submit_text: "Report Issue",
  success_message: "We got it — thanks!",
  issue_id: @issue_id,        # optional: link to a specific BugWatch issue
  metadata: { page: "checkout" }
) %>

Styling example (Tailwind)

.bugwatch-feedback-form { @apply space-y-4 max-w-md; }
.bugwatch-feedback-label { @apply block text-sm font-medium text-gray-700; }
.bugwatch-feedback-input,
.bugwatch-feedback-textarea { @apply w-full border rounded-lg px-3 py-2 text-sm; }
.bugwatch-feedback-submit { @apply bg-blue-600 text-white px-4 py-2 rounded-lg text-sm; }
.bugwatch-feedback-success { @apply text-green-600 text-sm; }
.bugwatch-feedback-error { @apply text-red-600 text-sm; }

Server-side feedback

You can also send feedback from Ruby (e.g. from a controller that handles your own form):

Bugwatch.send_feedback(
  params[:message],
  email: current_user.email,
  name:  current_user.name,
  url:   request.original_url
)

Database query tracking

The gem automatically subscribes to sql.active_record notifications and reports query performance data to your BugWatch instance. DB tracking is enabled by default — no extra setup required.

Configuration

# config/initializers/bugwatch.rb
Bugwatch.configure do |c|
  # ... existing config ...

  c.enable_db_tracking      = true   # default: true — set false to disable
  c.db_sample_rate          = 1.0    # 0.0–1.0 — fraction of requests to track (default: 1.0)
  c.db_query_threshold_ms   = 0      # only collect queries slower than this (default: 0 = all)
  c.max_queries_per_request = 200    # cap per request to limit overhead (default: 200)
end
Option Default Description
enable_db_tracking true Master switch for DB tracking
db_sample_rate 1.0 Fraction of requests whose queries are collected (0.0–1.0)
db_query_threshold_ms 0 Minimum query duration (ms) to collect — set higher to focus on slow queries
max_queries_per_request 200 Maximum queries stored per request

Schema operations and transaction bookkeeping (BEGIN, COMMIT, ROLLBACK) are automatically excluded. SQL literals are sanitized before sending, so no user data leaves your app.

Skipping tracking

Wrap any code block with Bugwatch.without_tracking to suppress all performance tracking (DB queries and transaction recording) for queries executed inside it. This is useful when BugWatch monitors itself, or for any internal bookkeeping queries you don't want tracked.

Bugwatch.without_tracking do
  SomeModel.insert_all(records)  # not tracked
end

In a controller:

around_action :skip_tracking

private

def skip_tracking(&block)
  Bugwatch.without_tracking(&block)
end

How it works

  1. Bugwatch::Middleware wraps your entire Rack stack.
  2. When an unhandled exception propagates out of a request, the middleware:
    • Captures the exception, full backtrace (with 3 lines of source context per in-app frame), request details, user context, and breadcrumbs.
    • POSTs the payload to your BugWatch instance in a background thread (fire-and-forget, 3s timeout).
    • Re-raises the exception so Rails error handling fires normally.
  3. Thread-local user context and breadcrumbs are cleared automatically after each request by the Rails around_action hook.

What gets sent

Field Description
exception.error_class Exception class name
exception.message Exception message
exception.backtrace Array of frames with file, line, method, in_app, source_context
request.* Method, URL, params (filtered), headers (filtered), IP
app.* Rails env, Ruby version, Rails version, git SHA, hostname
user.* ID, email, name, any custom fields
breadcrumbs Last 50 breadcrumbs with timestamp, type, message, metadata
duration_ms Request duration in milliseconds

Sensitive params (password, token, secret, key, auth, credit, card, cvv, ssn) are automatically filtered from request params and never sent.

Publishing

cd /home/max/bugwatch-ruby
gem build bugwatch-ruby.gemspec
gem signin
gem push bugwatch-ruby-0.1.0.gem