DebugBundle
SDKs

Ruby SDK

Install DebugBundle in Ruby, Rails, Rack, and Sidekiq applications with request, exception, log, probe, and browser relay capture.

The Ruby SDK ships as the debugbundle gem and supports Rails, Rack, Sidekiq, Ruby Logger, Semantic Logger, local file transport, connected HTTP transport, remote capture policy, probes, and a full browser relay handler.

Installation

gem "debugbundle"

Then install with Bundler:

bundle install

Configuration Reference

Configuration precedence is intentionally explicit:

  1. Values passed to DebugBundle.init(...), DebugBundle::Client.new(...), or DebugBundle::Relay::Handler.new(...).
  2. Rails config.debugbundle.* values when the Railtie configures the default client or relay route.
  3. Environment variables only when your application passes them into those Ruby calls.
  4. Server-owned capture policy and remote probe directives fetched from GET /v1/sdk/config.

Capture policy fields are server-owned. Do not set local SDK config fields for capture policy; configure capture policy in DebugBundle and let the SDK poll it.

OptionDefaultPurpose
project_tokenrequired for connected captureWrite-only DebugBundle project token.
serviceruby-serviceService name in event envelopes.
environmentdevelopmentRuntime environment label.
endpointhttps://api.debugbundle.com/v1/eventsConnected ingestion endpoint.
enabledtrueCapture kill switch.
project_modeconnectedconnected or local_only.
local_events_dir.debugbundle/local/eventsLocal event file destination.
spool_dir.debugbundle/local/browser-relay-spoolBrowser relay durable spool destination.
redact_fields[]Additional sensitive field names merged with built-in redaction defaults.
batch_size25Max events per flush batch.
flush_interval5Flush interval in seconds.
sample_rate1.0Per-event sampling rate.
log_levelwarningMinimum captured log severity.
relay_enabledtrueEnable the Rails relay route.
relay_rate_limit_per_minute60Per-IP browser relay rate limit.
relay_durable_writetrueWrite relay batches to spool before connected forwarding.
max_probe_labels50Max distinct probe labels retained in memory.
max_probe_entries_per_label10Ring buffer capacity per probe label.
probe_flush_on_errortrueAttach probe buffers to captured exceptions.
probes_poll_interval60Remote config poll interval in seconds.

Install Examples By Mode

Connected mode:

DebugBundle.init(
  project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
  service: "checkout-api",
  environment: "production",
  endpoint: "https://api.debugbundle.com/v1/events"
)

Local-only mode:

DebugBundle.init(
  project_token: ENV.fetch("DEBUGBUNDLE_TOKEN"),
  service: "checkout-api",
  environment: "development",
  project_mode: :local_only,
  local_events_dir: ".debugbundle/local/events"
)

Rails

Configure the SDK in an initializer:

# config/initializers/debugbundle.rb
Rails.application.configure do
  config.debugbundle.project_token = ENV["DEBUGBUNDLE_TOKEN"]
  config.debugbundle.service = "patients-api"
  config.debugbundle.environment = Rails.env
  config.debugbundle.project_mode = :connected
end

The Railtie inserts Rack request capture, preserves X-Request-Id and X-DebugBundle-Trace-Id, captures Rails route/controller/action metadata when available, wires Rails logger capture, reuses Rails filter_parameters as additional redaction keys, and mounts the browser relay route at POST /debugbundle/browser by default.

You can adjust relay behavior in the same config block:

Rails.application.configure do
  config.debugbundle.relay_enabled = true
  config.debugbundle.relay_path = "/debugbundle/browser"
  config.debugbundle.relay_allowed_origins = ["https://app.example.com"]
  config.debugbundle.relay_rate_limit_per_minute = 60
  config.debugbundle.relay_rate_limit_store = Rails.cache
end

Rack

Use the Rack middleware directly in non-Rails apps:

require "debugbundle"

DebugBundle.init(
  project_token: ENV["DEBUGBUNDLE_TOKEN"],
  service: "checkout-api",
  environment: "production"
)

use DebugBundle::Rack::Middleware, client: DebugBundle.client

The middleware captures request method, path, sanitized allowlisted headers, response status, duration, request ID, trace ID, exceptions, and recent probe buffers. It preserves downstream responses and re-raises exceptions after capture.

Sidekiq

Register the server middleware:

require "debugbundle"
require "debugbundle/sidekiq/server_middleware"

DebugBundle.init(
  project_token: ENV["DEBUGBUNDLE_TOKEN"],
  service: "billing-worker",
  environment: "production"
)

Sidekiq.configure_server do |config|
  config.server_middleware do |chain|
    chain.add DebugBundle::Sidekiq::ServerMiddleware
  end
end

Sidekiq events include job class, queue, jid, retry count, sanitized argument type summaries, exception details, runtime facts, and trace IDs when present on the job payload. The middleware never swallows job exceptions, so Sidekiq retry and failure behavior remains intact.

Vanilla Ruby

require "debugbundle"

DebugBundle.init(
  project_token: ENV["DEBUGBUNDLE_TOKEN"],
  service: "ruby-service",
  environment: "production"
)

DebugBundle.capture_exception(RuntimeError.new("boom"))
DebugBundle.capture_log("payment retry failed", level: :warning, context: { order_id: "ord_123" })
DebugBundle.capture_message("worker started")
DebugBundle.set_context(:account_id, "acct_123")
DebugBundle.probe("checkout.cart", { item_count: 3 })
DebugBundle.flush

DebugBundle.init arms best-effort Ruby exception capture through explicit at-exit and thread exception hooks. Ruby exception hooks cannot capture every hosting model; Rails, Rack, and Sidekiq integrations are the primary production capture paths.

Logger Integrations

Ruby Logger capture is additive and preserves existing output:

logger = Logger.new($stdout)
DebugBundle.capture_logger(logger)

logger.warn("retrying charge", order_id: "ord_123")

Semantic Logger is supported when the gem is present:

DebugBundle.capture_semantic_logger

Rails logger capture is auto-registered by the Railtie.

Browser Relay

The Ruby SDK includes a full browser relay handler for backend-owned browser event delivery:

  • DebugBundle::Relay::Handler for framework-neutral handling,
  • DebugBundle::Rack::RelayMiddleware for Rack apps,
  • the Rails Railtie-mounted route at POST /debugbundle/browser.

The relay validates same-origin or configured origins, requires Content-Type: application/json, rejects bodies over 256 KB, accepts only browser event types, strips browser-supplied credentials and trust fields, forces sdk_name to @debugbundle/sdk-browser, preserves browser correlation fields, rate limits per IP, writes local-only files, writes connected durable spool files by default, and forwards connected events with the server-side project token.

For split frontend/backend hosts, set explicit allowed origins. For connected relay delivery, a missing token means forwarding cannot succeed; keep the route disabled until server-side credentials are configured. To disable the relay, leave the route unmounted or set relay_enabled = false.

Transport Modes

ModeBehavior
Local/development/testWrites event batches to .debugbundle/local/events/
project_mode: :local_onlyWrites event batches to .debugbundle/local/events/
Connected production/stagingSends event batches to POST /v1/events and fetches GET /v1/sdk/config

Local files use owner-only permissions, canonical path validation, symlink checks, unpredictable temp names, and atomic temp-file rename.

Probes And Capture Policy

The Ruby SDK fetches server-owned capture policy and probe configuration from GET /v1/sdk/config in connected production/staging environments. It supports ETag refreshes, minimal fallback when config fetch fails, always-on probe ring buffers, remote probe activations, heavy probes, and request-scoped trigger tokens via _debug_probe or X-DebugBundle-Probe-Trigger.

DebugBundle.probe("checkout.tax", -> { expensive_tax_state }, heavy: true)

Heavy probes stay dormant unless a matching remote directive or trigger token is active.

Privacy Defaults

Ruby defaults are conservative for healthcare, financial, and enterprise systems:

  • request and response bodies are off by default,
  • request headers are allowlisted,
  • sensitive fields are recursively redacted before buffering or transport,
  • Rails filter_parameters are merged into redaction rules,
  • existing request IDs are preserved,
  • X-DebugBundle-Trace-Id links browser and backend events,
  • SDK failures are swallowed internally and never raise into host application code.

Runtime Support

SurfaceMinimum compatibility versionRecommended production versionInstalled-base compatibility laneRolling CI laneOut of scope
Ruby runtime3.1current maintained Ruby 3.4.x patch line3.1 and 3.2 remain supported for installed-base coverage3.1, 3.2, 3.3, 3.43.0 and older
Rails7.0latest 7.1 patch line7.0 compatibility support7.0 and 7.16.x and older
Rack2.2latest 3.x patch line2.2 compatibility support2.2 and 3.x2.1 and older
Sidekiq7.xlatest 8.x patch line7.x compatibility support7.x and 8.x6.x and older

Ruby 3.1 compatibility is maintained for the Rails installed base, but current upstream-maintained Ruby branches are recommended for production security fixes.

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.

  • Pin one debugbundle version across Ruby web apps 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 deployment examples.

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 and DebugBundle.status reports :degraded.
  • DebugBundle.init(enabled: false) keeps the SDK as a no-op and DebugBundle.status reports :disconnected.
  • DebugBundle.last_event_at stays nil until a successful flush completes.
  • DebugBundle.flush is a no-op when the SDK has no buffered events, no transport, or is still waiting out a retry window.

Status values:

  • :healthy means idle or the last flush succeeded.
  • :degraded means missing token or a temporary rate-limit window is preventing immediate delivery.
  • :disconnected means the SDK is disabled or repeated transport failures exhausted the connection path.

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.capture_message("debugbundle first-event verification", level: :error)
DebugBundle.flush
puts [DebugBundle.status, DebugBundle.last_event_at].inspect

Then confirm receipt through your mock ingestion endpoint, a staging project, or the DebugBundle CLI verification flow. The Ruby SDK repository also ships make smoke and make smoke-published VERSION=... to verify the built and published gem paths with a Rack app event plus browser relay batch.

On this page