chore(ruby-sdk): remove migration guides and Sidekiq-specific content

Remove experimental content that needs more polish before shipping:

- Delete references/migration.md entirely (AppSignal/Honeybadger migration
  guides with API mapping tables and dual-capture shims)
- Remove Sidekiq standalone init section, sentry-sidekiq gem references,
  and Sidekiq detection commands from SKILL.md
- Remove Sidekiq metrics sections from metrics.md (custom server middleware
  for per-job metrics, aggregate queue stats poller thread, and the
  'detecting existing metric patterns' scanner)
- Remove Sidekiq tracing section and Sidekiq-Cron integration from
  tracing.md and crons.md
- Clean up recommendation table to remove Sidekiq-dependent triggers

The skill now focuses on Rails, Sinatra, and Rack — the core Ruby web
stack. Sidekiq and migration support can be added back once properly
vetted.
This commit is contained in:
Daniel Griesser
2026-02-26 18:10:10 +01:00
parent deda2356f0
commit bd90254046
5 changed files with 7 additions and 325 deletions
+5 -38
View File
@@ -1,6 +1,6 @@
---
name: sentry-ruby-sdk
description: Full Sentry SDK setup for Ruby. Use when asked to add Sentry to Ruby, install sentry-ruby, setup Sentry in Rails/Sinatra/Rack, or configure error monitoring, tracing, logging, metrics, profiling, or crons for Ruby applications. Also handles migration from AppSignal or Honeybadger. Supports Rails, Sinatra, Rack, Sidekiq, and Resque.
description: Full Sentry SDK setup for Ruby. Use when asked to add Sentry to Ruby, install sentry-ruby, setup Sentry in Rails/Sinatra/Rack, or configure error monitoring, tracing, logging, metrics, profiling, or crons for Ruby applications. Supports Rails, Sinatra, and Rack.
license: Apache-2.0
---
@@ -13,8 +13,7 @@ Opinionated wizard that scans the project and guides through complete Sentry set
- User asks to "add Sentry to Ruby" or "set up Sentry" in a Ruby app
- User wants error monitoring, tracing, logging, metrics, profiling, or crons in Ruby
- User mentions `sentry-ruby`, `sentry-rails`, or the Ruby Sentry SDK
- User is migrating from AppSignal or Honeybadger to Sentry
- User wants to monitor exceptions, HTTP requests, or background jobs in Rails/Sinatra
- User wants to monitor exceptions or HTTP requests in Rails/Sinatra
> **Note:** SDK APIs below reflect sentry-ruby v6.4.0.
> Always verify against [docs.sentry.io/platforms/ruby/](https://docs.sentry.io/platforms/ruby/) before implementing.
@@ -30,26 +29,14 @@ grep -i sentry Gemfile 2>/dev/null
# Framework
grep -E '"rails"|"sinatra"' Gemfile 2>/dev/null
# Background jobs
grep -E '"sidekiq"|"resque"|"delayed_job"' Gemfile 2>/dev/null
# Competitor monitoring tools — triggers migration path if found
grep -E '"appsignal"|"honeybadger"' Gemfile 2>/dev/null
# Existing metric patterns (StatsD, Datadog, Prometheus)
grep -rE "(statsd|dogstatsd|prometheus|\.gauge|\.histogram|\.increment|\.timing)" \
app/ lib/ --include="*.rb" 2>/dev/null | grep -v "_spec\|_test" | head -20
# Companion frontend
cat package.json frontend/package.json web/package.json 2>/dev/null | grep -E '"@sentry|"sentry-'
```
**Route from what you find:**
- **Competitor detected** (`appsignal`, `honeybadger`) → load `references/migration.md` first; **delete the competitor initializer** (`config/initializers/honeybadger.rb` or `config/initializers/appsignal.rb`) as part of migration
- **Sentry already present** → skip to Phase 2 to configure features
- **Rails** → use `sentry-rails` + `config/initializers/sentry.rb`
- **Rack/Sinatra** → `sentry-ruby` + `Sentry::Rack::CaptureExceptions` middleware
- **Sidekiq** → add `sentry-sidekiq`; recommend Metrics if existing metric patterns found
---
@@ -62,9 +49,9 @@ Lead with a concrete proposal — don't ask open-ended questions:
| Error Monitoring | **Always** |
| Tracing | Rails / Sinatra / Rack / any HTTP framework |
| Logging | **Always**`enable_logs: true` costs nothing |
| Metrics | Sidekiq present; existing metric lib (StatsD, Prometheus) detected |
| Metrics | Business KPIs, SLO tracking, or custom counters needed |
| Profiling | ⚠️ Beta — performance profiling requested; requires `stackprof` or `vernier` gem |
| Crons | Scheduled jobs detected (ActiveJob, Sidekiq-Cron, Clockwork, Whenever) |
| Crons | Scheduled jobs detected (ActiveJob, Clockwork, Whenever) |
Propose: *"I recommend Error Monitoring + Tracing + Logging [+ Metrics if applicable]. Shall I proceed?"*
@@ -79,9 +66,6 @@ Propose: *"I recommend Error Monitoring + Tracing + Logging [+ Metrics if applic
# Gemfile
gem "sentry-ruby"
gem "sentry-rails"
gem "sentry-sidekiq" # if using Sidekiq
gem "sentry-resque" # if using Resque
gem "sentry-delayed_job" # if using DelayedJob
```
**Rack / Sinatra / plain Ruby:**
@@ -124,21 +108,6 @@ end
use Sentry::Rack::CaptureExceptions # in config.ru, before app middleware
```
### Init — Sidekiq standalone
```ruby
require "sentry-ruby"
require "sentry-sidekiq"
Sentry.init do |config|
config.dsn = ENV["SENTRY_DSN"]
config.spotlight = ENV.fetch("RAILS_ENV", "development") == "development"
config.breadcrumbs_logger = [:sentry_logger]
config.traces_sample_rate = 1.0
config.enable_logs = true
end
```
### Environment variables
```bash
@@ -153,11 +122,10 @@ Load each reference when implementing the corresponding feature:
| Feature | Reference | Load when... |
|---------|-----------|-------------|
| Migration | `references/migration.md` | Competitor gem found — load **before** installing Sentry |
| Error Monitoring | `references/error-monitoring.md` | Always |
| Tracing | `references/tracing.md` | HTTP handlers / distributed tracing |
| Logging | `references/logging.md` | Structured log capture |
| Metrics | `references/metrics.md` | Sidekiq present; existing metric patterns |
| Metrics | `references/metrics.md` | Business KPIs, SLO tracking |
| Profiling | `references/profiling.md` | Performance profiling requested (beta) |
| Crons | `references/crons.md` | Scheduled jobs detected or requested |
@@ -240,7 +208,6 @@ For trace stitching between Ruby backend and JS frontend, see `references/tracin
| Events not appearing | `config.debug = true`; verify DSN; ensure `Sentry.init` before first request |
| Rails exceptions missing | Must use `sentry-rails``sentry-ruby` alone doesn't hook Rails error handlers |
| No traces | Set `traces_sample_rate > 0`; ensure `sentry-rails` or `Sentry::Rack::CaptureExceptions` |
| Sidekiq jobs not traced | Add `sentry-sidekiq` gem |
| Missing request context | Set `config.send_default_pii = true` |
| Logs not appearing | Set `config.enable_logs = true`; sentry-ruby ≥ 5.24.0 required |
| Metrics not appearing | Check `enable_metrics` is not `false`; verify DSN |
+1 -15
View File
@@ -8,7 +8,6 @@ Cron monitoring detects missed, failed, or slow scheduled jobs by capturing chec
- [Manual check-ins](#manual-check-ins)
- [ActiveJob integration](#activejob-integration)
- [Sidekiq-Cron integration](#sidekiq-cron-integration)
- [Upserting monitor configuration](#upserting-monitor-configuration)
- [Heartbeat pattern](#heartbeat-pattern)
- [Best Practices](#best-practices)
@@ -78,19 +77,6 @@ class NightlyCleanupJob < ApplicationJob
end
```
## Sidekiq-Cron Integration
Enable automatic check-ins for all Sidekiq-Cron periodic jobs with a single patch:
```ruby
Sentry.init do |config|
config.dsn = ENV["SENTRY_DSN"]
config.enabled_patches += [:sidekiq_cron]
end
```
Sentry captures check-ins for every job defined in your Sidekiq-Cron schedule automatically — no per-job changes needed.
## Upserting Monitor Configuration
Pass `monitor_config` in the initial check-in to create or update the monitor definition programmatically (no manual setup in Sentry UI required):
@@ -164,5 +150,5 @@ Heartbeats detect when a job doesn't run at all but cannot detect runtime overag
| Monitor shows "missed" immediately | `checkin_margin` too low; increase it to account for scheduler jitter |
| `capture_check_in` returns `nil` | SDK not initialized — ensure `Sentry.init` runs before the job |
| ActiveJob mixin not capturing | Confirm `include Sentry::Cron::MonitorCheckIns` and `sentry_monitor_check_ins` are both present |
| Sidekiq-Cron not auto-capturing | Ensure `config.enabled_patches += [:sidekiq_cron]` is in `Sentry.init`; requires `sidekiq-cron` gem |
| Duplicate check-in pairs | Check that `capture_check_in` is not called in both the mixin and manual code for the same job |
+1 -85
View File
@@ -8,8 +8,6 @@
- [Configuration](#configuration)
- [Metric Types](#metric-types)
- [Unit Reference](#unit-reference)
- [Sidekiq Metrics](#sidekiq-metrics)
- [Detecting Existing Metric Patterns](#detecting-existing-metric-patterns)
- [`before_send_metric` Hook](#before_send_metric-hook)
- [Best Practices](#best-practices)
- [Troubleshooting](#troubleshooting)
@@ -40,8 +38,8 @@ Sentry.metrics.count("user.signup", attributes: { plan: "pro" })
### Gauge — current value (can go up or down)
```ruby
Sentry.metrics.gauge("sidekiq.queue.depth", Sidekiq::Stats.new.enqueued)
Sentry.metrics.gauge("cache.size", Rails.cache.stats[:curr_items])
Sentry.metrics.gauge("connections.active", ActiveRecord::Base.connection_pool.connections.size)
```
### Distribution — statistical spread of a value
@@ -62,86 +60,6 @@ Sentry.metrics.distribution("db.query_time", query_ms, unit: "millisecond",
| Fractions | `"ratio"`, `"percent"` |
| None | `"none"` (default) |
## Sidekiq Metrics
Two complementary approaches cover different aspects of Sidekiq observability:
### Option A — Server middleware (per-job metrics)
A Sidekiq server middleware fires for every job execution — the right tool for job duration, throughput, and error rate broken down by queue and worker class.
```ruby
# lib/sentry_job_metrics.rb
class SentryJobMetrics
def call(worker, job, queue)
start = Time.now
yield
attrs = { queue: queue, worker: worker.class.name }
Sentry.metrics.distribution("sidekiq.job.duration",
(Time.now - start) * 1000, unit: "millisecond", attributes: attrs)
Sentry.metrics.count("sidekiq.job.success", attributes: attrs)
rescue => e
Sentry.metrics.count("sidekiq.job.failure",
attributes: { queue: queue, worker: worker.class.name })
raise
end
end
# config/initializers/sidekiq.rb
Sidekiq.configure_server do |config|
config.server_middleware do |chain|
chain.add SentryJobMetrics
end
end
```
**What this gives you:** `sidekiq.job.duration` (p50/p95/p99 per queue + worker), `sidekiq.job.success` and `sidekiq.job.failure` counters.
**What it cannot give you:** queue depth, queue latency (oldest job age), retry/dead queue sizes — these are aggregate stats that require polling `Sidekiq::Stats`.
### Option B — Aggregate queue stats (periodic sampling)
For queue depth and latency, poll `Sidekiq::Stats` on a schedule. A lightweight background thread or a recurring Sidekiq job both work:
```ruby
# config/initializers/sentry_sidekiq_stats.rb
Thread.new do
loop do
begin
stats = Sidekiq::Stats.new
Sentry.metrics.gauge("sidekiq.enqueued", stats.enqueued)
Sentry.metrics.gauge("sidekiq.retries", stats.retry_size)
Sentry.metrics.gauge("sidekiq.dead", stats.dead_size)
Sidekiq::Queue.all.first(10).each do |q|
attrs = { queue: q.name }
Sentry.metrics.gauge("sidekiq.queue.depth", q.size, attributes: attrs)
Sentry.metrics.gauge("sidekiq.queue.latency", q.latency,
unit: "second", attributes: attrs)
end
rescue => e
# don't crash the thread on transient Redis errors
end
sleep 30
end
end
```
**Use both together** for complete Sidekiq visibility: the middleware captures per-job detail, the poller captures queue health over time.
## Detecting Existing Metric Patterns
Before adding Sentry metrics, scan for existing instrumentation to migrate or complement:
```bash
# StatsD / Datadog / Prometheus calls
grep -rE "(statsd|dogstatsd|prometheus|\.gauge|\.distribution|\.histogram|\.increment|\.timing)" \
app/ lib/ --include="*.rb" | grep -v "_spec\|_test"
# Sidekiq::Stats usage (shows what's already being tracked)
grep -rn "Sidekiq::Stats\|Sidekiq::Queue" app/ lib/ --include="*.rb"
```
## `before_send_metric` Hook
```ruby
@@ -178,5 +96,3 @@ end
| Metrics not in Sentry | Verify `enable_metrics` is not `false`; check DSN |
| `count` values look wrong | Sentry diffs lifetime counters — reporting deltas directly avoids confusion |
| `before_send_metric` not filtering | Return `nil`, not `false`, to drop a metric |
| Per-job breakdown missing | Ensure `SentryJobMetrics` middleware is added to `server_middleware`, not `client_middleware` |
| Queue depth always zero | Verify the stats polling thread is running; check Redis connectivity |
@@ -1,178 +0,0 @@
# Migrating to Sentry — Ruby SDK
> Minimum SDK: `sentry-ruby` v5.0.0+ (Rails: also add `sentry-rails`)
> Covers migrations from: AppSignal, Honeybadger
## Contents
- [Step 1: Detect What's in the Codebase](#step-1-detect-whats-in-the-codebase)
- [AppSignal → Sentry](#appsignal--sentry)
- [Honeybadger → Sentry](#honeybadger--sentry)
- [Universal Migration Checklist](#universal-migration-checklist)
- [Troubleshooting](#troubleshooting)
## Step 1: Detect What's in the Codebase
```bash
# Find competitor gems
grep -E '"appsignal"|"honeybadger"' Gemfile Gemfile.lock 2>/dev/null
# Find call sites across the app
grep -rn "Appsignal\.\|Honeybadger\." \
app/ lib/ config/ --include="*.rb" | grep -v "_spec\|_test"
# Find config files to remove after migration
ls config/appsignal.yml \
config/honeybadger.yml .honeybadger.yml 2>/dev/null
```
---
## AppSignal → Sentry
**Gemfile:**
```ruby
# Remove:
gem "appsignal"
# Add:
gem "sentry-ruby"
gem "sentry-rails" # if Rails
gem "sentry-sidekiq" # if Sidekiq
```
**Delete:** `config/appsignal.yml`, `config/initializers/appsignal.rb`
### API mapping
| AppSignal | Sentry |
|-----------|--------|
| `Appsignal.report_error(e)` | `Sentry.capture_exception(e)` |
| `Appsignal.send_error(e)` | `Sentry.capture_exception(e)` |
| `Appsignal.set_error(e)` | `Sentry.capture_exception(e)` |
| `Appsignal.listen_for_error { }` | `begin … rescue => e; Sentry.capture_exception(e); raise; end` |
| `Appsignal.tag_request(key: val)` | `Sentry.set_tags(key: val)` |
| `Appsignal.add_tags(key: val)` | `Sentry.set_tags(key: val)` |
| `Appsignal.add_custom_data(hash)` | `Sentry.set_context("custom", hash)` |
| `Appsignal.set_action("name")` | `Sentry.get_current_scope.set_transaction_name("name")` |
| `Appsignal.add_breadcrumb(cat, action, msg)` | `Sentry.add_breadcrumb(Sentry::Breadcrumb.new(category: cat, message: msg))` |
| `Appsignal.instrument("name") { }` | `Sentry.with_child_span(op: "name") { }` |
| `Appsignal.set_gauge("m", val, tags)` | `Sentry.metrics.gauge("m", val, attributes: tags)` |
| `Appsignal.increment_counter("m", val, tags)` | `Sentry.metrics.count("m", value: val, attributes: tags)` |
### Find call sites
```bash
grep -rn "Appsignal\.\(report_error\|send_error\|set_error\|listen_for_error\|tag_request\|add_tags\|add_custom_data\|instrument\|set_gauge\|increment_counter\)" \
app/ lib/ --include="*.rb"
```
### Initializer
```ruby
# config/initializers/sentry.rb
Sentry.init do |config|
config.dsn = ENV["SENTRY_DSN"]
config.breadcrumbs_logger = [:active_support_logger, :http_logger]
config.send_default_pii = true
config.traces_sample_rate = 1.0
config.enable_logs = true
end
```
---
## Honeybadger → Sentry
**Gemfile:**
```ruby
# Remove:
gem "honeybadger"
# Add:
gem "sentry-ruby"
gem "sentry-rails"
```
**Delete:** `config/honeybadger.yml`, `.honeybadger.yml`, `config/initializers/honeybadger.rb`
### API mapping
| Honeybadger | Sentry |
|-------------|--------|
| `Honeybadger.notify(e)` | `Sentry.capture_exception(e)` |
| `Honeybadger.notify("message")` | `Sentry.capture_message("message")` |
| `Honeybadger.notify(e, context: hash)` | `Sentry.with_scope { \|s\| s.set_context("ctx", hash); Sentry.capture_exception(e) }` |
| `Honeybadger.context(key: val)` | `Sentry.set_tags(key: val)` |
| `Honeybadger.context { \|c\| c[:key] = val }` | `Sentry.configure_scope { \|s\| s.set_context("app", {key: val}) }` |
| `Honeybadger.context.clear!` | `Sentry.get_current_scope.clear` |
| `Honeybadger.add_breadcrumb(msg, metadata: h)` | `Sentry.add_breadcrumb(Sentry::Breadcrumb.new(message: msg, data: h))` |
| `Honeybadger.exception_filter { \|n\| n.halt! if … }` | `config.before_send = lambda { \|e, _h\| nil if … }` |
### Find call sites
```bash
grep -rn "Honeybadger\.\(notify\|context\|add_breadcrumb\|exception_filter\)" \
app/ lib/ --include="*.rb"
```
---
## Universal Migration Checklist
Works for any tool not covered above:
```bash
# Error capture
grep -rn "\.\(notify\|report_error\|send_error\|notice_error\)" \
app/ lib/ --include="*.rb" | grep -v "_spec\|_test"
# Context / tagging
grep -rn "\.\(context\|tag_request\|add_tags\|add_custom_attributes\)" \
app/ lib/ --include="*.rb" | grep -v "_spec\|_test"
# Custom spans / instrumentation
grep -rn "\.\(instrument\|monitor\|in_transaction\)" \
app/ lib/ --include="*.rb" | grep -v "_spec\|_test"
# Metric calls
grep -rn "\.\(set_gauge\|increment_counter\|record_metric\|gauge\|histogram\|timing\)" \
app/ lib/ --include="*.rb" | grep -v "_spec\|_test"
# Environment variables to update
grep -rn "APPSIGNAL\|HONEYBADGER" \
.env .env.* config/ --include="*.rb" --include="*.yml" 2>/dev/null
```
### Environment variable mapping
| Tool | Old env var | Sentry |
|------|-------------|--------|
| AppSignal | `APPSIGNAL_PUSH_API_KEY` | `SENTRY_DSN` |
| Honeybadger | `HONEYBADGER_API_KEY` | `SENTRY_DSN` |
### Rollout strategy
Run both tools in parallel for one release cycle, then remove the old gem once Sentry is receiving events in production.
```ruby
# Temporary dual-capture shim — remove after rollout validation:
module ErrorCapture
def self.capture(exception, context: {})
Sentry.with_scope do |scope|
scope.set_context("extra", context) unless context.empty?
Sentry.capture_exception(exception)
end
OldTool.notify(exception) rescue nil # replace OldTool with actual constant
end
end
```
## Troubleshooting
| Issue | Solution |
|-------|----------|
| Missing errors after migration | Ensure `sentry-rails` is present — `sentry-ruby` alone doesn't hook Rails error handlers |
| Context missing from events | Old tools often set context via middleware; replicate with a `before_action` calling `Sentry.set_user` / `Sentry.set_tags` |
| Old gem still loading | Check `Gemfile.lock` — it may be a transitive dependency |
| Distributed traces broken | Ensure all services have migrated and propagate `sentry-trace` + `baggage` headers |
@@ -36,7 +36,6 @@ Sentry.init do |config|
when /health/ then 0.0 # drop health checks
else 0.1
end
when /sidekiq/ then 0.01
else 0.0
end
end
@@ -63,10 +62,6 @@ use Sentry::Rack::CaptureExceptions
Wraps each Rack request in a transaction.
### Sidekiq (via `sentry-sidekiq`)
No extra code. Each worker execution becomes a transaction, inheriting distributed trace context from the enqueuing request.
## Custom Instrumentation
### Wrap a block in a child span (preferred)
@@ -209,9 +204,6 @@ Sentry becomes a Span Exporter and Propagator — existing OTel instrumentation
| ActiveRecord | `sentry-rails` | SQL queries → spans |
| ActionMailer | `sentry-rails` | Mail delivery → spans |
| ActiveJob | `sentry-rails` | Job execution → spans |
| Sidekiq workers | `sentry-sidekiq` | Worker execution → transactions |
| Resque workers | `sentry-resque` | Worker execution → transactions |
| DelayedJob | `sentry-delayed_job` | Job execution → transactions |
| Net::HTTP | `sentry-ruby` | Outbound HTTP → spans + header propagation |
| Redis | `sentry-ruby` | Redis commands → spans (needs `:redis_logger`) |
| GraphQL | `sentry-ruby` | Queries → transactions (enable with `enabled_patches`) |
@@ -229,7 +221,6 @@ Sentry becomes a Span Exporter and Propagator — existing OTel instrumentation
| Issue | Solution |
|-------|----------|
| No transactions in dashboard | Set `traces_sample_rate > 0`; ensure `sentry-rails` or Rack middleware is present |
| Sidekiq jobs not traced | Add `sentry-sidekiq` gem; no other config needed |
| Missing DB spans | Ensure `sentry-rails` is loaded (it patches ActiveRecord) |
| Distributed trace not stitching | Verify `sentry-trace` + `baggage` headers are forwarded by all services |
| Frontend trace not linking | Add `<%= Sentry.get_trace_propagation_meta.html_safe %>` to your HTML `<head>` |