debugbundle
Ruby SDK for DebugBundle.
Use this gem to capture Ruby backend exceptions, request metadata, structured logs, runtime context, probe data, and browser relay traffic. It supports a singleton facade plus instance clients for Rack, Rails, Sidekiq, and explicit Ruby instrumentation.
Installation
gem "debugbundle"
Quick Start
require "debugbundle"
require "logger"
DebugBundle.init(
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
service: "checkout-api",
environment: ENV.fetch("APP_ENV", "production")
)
DebugBundle.capture_logger(Logger.new($stdout))
begin
perform_checkout
rescue => error
DebugBundle.capture_exception(error, context: { order_id: 123 })
end
DebugBundle.("worker started", level: :info)
DebugBundle.flush
DebugBundle.init(...) arms best-effort process exception capture automatically through at_exit and thread exception hooks.
Framework Integrations
| Surface | Integration |
|---|---|
| Rack | DebugBundle::Rack::Middleware |
| Rails | Railtie bootstrap, Rack middleware, and auto-mounted relay route |
| Sidekiq | DebugBundle::Sidekiq::ServerMiddleware |
| Ruby Logger | DebugBundle.capture_logger(logger) |
| Semantic Logger | DebugBundle.capture_semantic_logger |
| Browser relay | DebugBundle::Relay::Handler or DebugBundle::Rack::RelayMiddleware |
Configuration Reference
Configuration sources and precedence:
- Explicit arguments passed to
DebugBundle.init(...),DebugBundle::Client.new(...), orDebugBundle::Relay::Handler.new(...). - Rails
config.debugbundle.*values when the Railtie wires the default client or relay route. - Environment variables only when your application chooses to pass them into those explicit Ruby calls. The gem does not auto-read arbitrary config env vars on its own.
- Remote probe directives and capture policy returned by
GET /v1/sdk/configafter a connected client initializes.
Capture-policy fields are server-owned and must not be supplied in local SDK config. The Ruby SDK enforces the server response locally after initialization.
| Option | Default | Purpose |
|---|---|---|
project_token |
required for connected capture | Write-only DebugBundle project token used by server-side transport. |
service |
ruby-service |
Service name used in event envelopes. |
environment |
development |
Runtime environment. |
endpoint |
https://api.debugbundle.com/v1/events |
Connected ingestion endpoint. |
enabled |
true |
Disable all capture without removing instrumentation. |
project_mode |
connected |
connected or local_only. |
local_events_dir |
.debugbundle/local/events |
Local event file destination. |
spool_dir |
.debugbundle/local/browser-relay-spool |
Relay durable spool destination. |
redact_fields |
[] |
Additional sensitive field names merged with built-in redaction defaults. Rails filter_parameters are added automatically. |
batch_size |
25 |
Max events per flush batch. |
flush_interval |
5 |
Flush interval in seconds. |
sample_rate |
1.0 |
Fraction of events kept before transport. |
log_level |
warning |
Minimum captured log severity. |
relay_enabled |
true |
Enable relay handling when using the Rails helper surface. |
relay_rate_limit_per_minute |
60 |
Per-IP rate limit for browser relay requests. |
relay_durable_write |
true |
Write relay batches to the local spool before connected forwarding. |
max_probe_labels |
50 |
Max distinct probe labels kept in memory. |
max_probe_entries_per_label |
10 |
Max entries retained per probe label. |
probe_flush_on_error |
true |
Attach probe buffers to captured exceptions. |
probes_poll_interval |
60 |
Remote config poll interval in seconds. |
Install Examples by Mode
Connected mode
require "debugbundle"
DebugBundle.init(
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
service: "checkout-api",
environment: "production",
endpoint: "https://api.debugbundle.com/v1/events"
)
Local-only mode
require "debugbundle"
DebugBundle.init(
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
service: "checkout-api",
environment: "development",
project_mode: :local_only,
local_events_dir: ".debugbundle/local/events"
)
Rack middleware
require "debugbundle"
require "rack"
client = DebugBundle.init(
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
service: "checkout-api",
environment: "production"
)
app = Rack::Builder.new do
use DebugBundle::Rack::Middleware, client: client
run lambda { |_env|
[200, { "Content-Type" => "text/plain" }, ["ok"]]
}
end
Rails initializer
# config/initializers/debugbundle.rb
require "debugbundle"
DebugBundle.init(
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
service: "checkout-api",
environment: Rails.env
)
Rails.application.configure do
config.debugbundle.relay_allowed_origins = ["https://app.example.com"]
end
Sidekiq server middleware
require "debugbundle"
DebugBundle.init(
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
service: "checkout-worker",
environment: ENV.fetch("APP_ENV", "production")
)
Sidekiq.configure_server do |config|
config.server_middleware do |chain|
chain.add(DebugBundle::Sidekiq::ServerMiddleware, client: DebugBundle.client)
end
end
Logger integration
require "debugbundle"
require "logger"
DebugBundle.init(
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
service: "checkout-api"
)
logger = Logger.new($stdout)
DebugBundle.capture_logger(logger)
Runtime and Framework Support
| Surface | Minimum compatibility version | Recommended production version | Installed-base compatibility lane | Rolling CI lane | Out of scope |
|---|---|---|---|---|---|
| Ruby runtime | 3.1 | current maintained Ruby 3.4.x patch line | 3.1 and 3.2 remain supported for installed-base coverage | 3.1, 3.2, 3.3, 3.4 | 3.0 and older |
| Rails | 7.0 | latest 7.1 patch line | 7.0 compatibility support | 7.0 and 7.1 | 6.x and older |
| Rack | 2.2 | latest 3.x patch line | 2.2 compatibility support | 2.2 and 3.x | 2.1 and older |
| Sidekiq | 7.x | latest 8.x patch line | 7.x compatibility support | 7.x and 8.x | 6.x and older |
Post-V1 integrations remain out of scope here: Resque, Delayed Job, GoodJob, Sneakers, Shoryuken, Sinatra, Hanami, and deep ActiveRecord or SQL auto-instrumentation.
Dependency Alignment
debugbundle ships as one gem in V1, so there is no multi-package version-alignment surface like an npm family rule or Maven BOM.
- Pin one
debugbundleversion across your Ruby web app and worker repos when you want identical SDK behavior everywhere. - Keep Rack, Rails, and Sidekiq inside the supported lanes above.
- Do not mix unsupported framework majors into examples or deployment templates.
Browser Relay
Ruby backends can receive browser events at POST /debugbundle/browser through the relay handler.
Rails applications can let the Railtie append that route automatically, or override it with:
config.debugbundle.relay_enabled = falseto disable automatic mountingconfig.debugbundle.relay_path = "/debugbundle/browser"to change the mounted pathconfig.debugbundle.relay_allowed_origins = ["https://app.example.com"]to pin allowed originsconfig.debugbundle.relay_rate_limit_per_minute = 120to adjust per-IP rate limitingconfig.debugbundle.relay_rate_limit_store = Rails.cacheto share rate limiting across processesconfig.debugbundle.relay_handler = custom_handlerto supply a custom relay handler
Rack applications can mount the same handler explicitly:
relay_handler = DebugBundle::Relay::Handler.new(
project_mode: :connected,
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
endpoint: "https://api.debugbundle.com/v1/events",
allowed_origins: ["https://app.example.com"]
)
use DebugBundle::Rack::RelayMiddleware, handler: relay_handler
Relay behavior:
- same-origin is the safe default when you do not set explicit allowed origins
- use explicit allowed origins when the frontend and backend live on different hosts
- requests must use
Content-Type: application/json - request bodies are capped at 256 KB
- per-IP rate limiting defaults to 60 requests per minute
- browser-supplied DebugBundle credentials are stripped before delivery, preserving credential isolation
- browser
service,environment, and correlation fields are preserved unless you explicitly override them in the relay handler - local-only mode writes validated browser events to
.debugbundle/local/events - connected durable mode writes validated browser events to
.debugbundle/local/browser-relay-spoolbefore forwarding to the configured endpoint - set
relay_durable_write: falsewhen you intentionally want connected forwarding without the local spool write - to disable the relay entirely, leave the route unmounted or set
relay_enabled = false - a missing token means connected forwarding cannot succeed; treat that as a server config error and leave the route disabled until the server-side token is fixed
Remote Probes
Probe buffers stay local and flush on captured exceptions by default. Paid-tier projects can also activate probes for immediate probe_event shipping through the polled remote config.
For one-off request diagnostics, the Ruby SDK also accepts signed trigger tokens:
- header:
X-DebugBundle-Probe-Trigger: dbundle_probe_... - query parameter:
?_debug_probe=dbundle_probe_...
Matching probes still stay in the local ring buffer, but the triggered request also emits standalone probe_event records immediately when the token is valid.
Safety Defaults
- SDK failures are isolated from host application failures.
- Sensitive values are redacted before buffering or transport.
- Rails
filter_parametersare merged into redaction automatically. - Duplicate event storms are suppressed locally.
- Request headers use an allowlist by default.
- Local file writes use owner-only permissions.
development,local, andtestenvironments write local event files by default.- Browser relay requests cannot smuggle server-side credentials.
Service Naming
Use distinct service names when one DebugBundle project receives events from multiple deployables:
- Browser frontend:
checkout-web - Rails or Rack API:
checkout-api - Sidekiq worker:
checkout-worker
The Ruby relay preserves the browser-provided service name and environment by default. Only override relay-level service or environment when you intentionally want the backend relay host to rewrite browser event identity.
Safe Startup and Status
The SDK never raises host-facing exceptions because of missing config, bad transport responses, or malformed remote config payloads.
DebugBundle.init(project_token: "")leaves capture disabled andDebugBundle.statusreports:degradedDebugBundle.init(enabled: false)keeps the SDK as a no-op andDebugBundle.statusreports:disconnectedDebugBundle.last_event_atstaysniluntil a successful flush completesDebugBundle.flushis a no-op when the SDK has no buffered events, no transport, or is still waiting out a retry window
Status meanings:
:healthy— idle or the last flush succeeded:degraded— missing token or a temporary rate-limit window is preventing immediate delivery:disconnected— the SDK is disabled or repeated transport failures exhausted the connection path
The release rule here is fail-safe, not fail-open: connected mode with a missing token must never pretend capture is healthy.
First-Event Verification
Use an explicit test message or exception during setup:
require "debugbundle"
DebugBundle.init(
project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
service: "debugbundle-first-event",
environment: "staging"
)
DebugBundle.("debugbundle first-event verification", level: :error)
DebugBundle.flush
puts [DebugBundle.status, DebugBundle.last_event_at].inspect
Then confirm the event through your mock ingestion endpoint, a staging project, or the DebugBundle CLI verification flow.
This repository also ships a clean-install app-driven smoke harness that validates the built gem and the published gem path:
make smoke
make smoke-published VERSION=0.1.0
make smoke builds the gem, installs it into a fresh RubyGems home, drives a Rack request plus a browser relay batch through the public SDK surface, validates event envelope shape, and confirms the mock ingestion endpoint receives the expected service, environment, SDK metadata, and correlation fields.
Examples
- Rack app: examples/rack_app.rb
- Rails initializer: examples/rails_initializer.rb
- Sidekiq server setup: examples/sidekiq_initializer.rb
Development
The project defaults to Docker-backed commands:
make bundle-install
make test
make compat
make lint
make build
make smoke
CI validates RSpec, RuboCop, compatibility lanes, gem build, and the clean-install smoke harness.
Release
The repository ships a GitHub Actions release workflow at .github/workflows/release.yml.
- Push a
v*tag or run the workflow manually with aversioninput. - Configure the
RUBYGEMS_API_KEYrepository secret before enabling publish. - The workflow runs lint, tests, gem build,
make smoke, RubyGems publish, andmake smoke-published VERSION=<tag>before creating the GitHub release.
Documentation
- Ruby SDK docs: https://debugbundle.com/docs/sdks/ruby
- SDK overview: https://debugbundle.com/docs/sdks
- Browser relay: https://debugbundle.com/docs/sdks/browser-relay
- Repository: https://github.com/debugbundle/debugbundle-ruby
License
AGPL-3.0-only. See LICENSE.