Skip to main content

Rails Integration

The Brainz Lab SDK provides deep integration with Rails.

Automatic Features

When you install the SDK in a Rails app, you automatically get:

Request Context

Every log includes request information:
# Your code
BrainzLab::Recall.info("Something happened")

# What's captured
{
  message: "Something happened",
  context: {
    request_id: "abc-123-def",
    path: "/users/1",
    method: "GET",
    controller: "UsersController",
    action: "show",
    format: "html"
  }
}

Error Capture

Unhandled exceptions are automatically reported to Reflex with zero configuration:
# This error is automatically captured
def show
  @user = User.find(params[:id])
end

# ActiveRecord::RecordNotFound is sent to Reflex
# with full request context, breadcrumbs, and user info
The SDK hooks into multiple Rails error capture mechanisms:
  • Rails 7+ ErrorReporter - Subscribes to Rails.error.subscribe
  • Controller rescue_from - Captures controller exceptions
  • ActiveJob errors - Captures background job failures
  • Sidekiq errors - Captures Sidekiq job failures (if Sidekiq is present)

User Tracking

Set the current user and it’s included everywhere:
class ApplicationController < ActionController::Base
  before_action :set_brainzlab_user

  private

  def set_brainzlab_user
    return unless current_user

    BrainzLab.set_user(
      id: current_user.id,
      email: current_user.email,
      name: current_user.name
    )
  end
end

ActiveRecord Integration

Query Logging

SQL queries are captured as breadcrumbs:
User.find(123)
# Breadcrumb: SELECT * FROM users WHERE id = 123 (2.3ms)

Slow Query Alerts

Log slow queries:
BrainzLab.configure do |config|
  config.recall_slow_query_threshold = 100  # ms
end

# Logs warning for queries > 100ms

ActiveJob Integration

Background jobs are automatically instrumented:
class PaymentJob < ApplicationJob
  def perform(order_id)
    # Context automatically includes:
    # - job_class: "PaymentJob"
    # - job_id: "abc-123"
    # - queue: "default"

    BrainzLab::Recall.info("Processing payment", order_id: order_id)
  end
end

Error Tracking in Jobs

Job errors are captured with full context:
class ImportJob < ApplicationJob
  def perform(file_path)
    import_data(file_path)
  rescue ImportError => e
    # Automatically captured with:
    # - Job class, ID, queue
    # - Arguments
    # - Retry count
    raise
  end
end

Sidekiq Integration

Sidekiq is automatically detected and configured. No additional setup required:
class HardWorker
  include Sidekiq::Job

  def perform(user_id)
    # Context includes Sidekiq metadata
    BrainzLab::Recall.info("Working hard", user_id: user_id)
  end
end
When errors occur in Sidekiq jobs, they’re captured with:
  • Job class name
  • Job ID (jid)
  • Queue name
  • Job arguments (first 5, for safety)
  • Retry count

Action Cable Integration

WebSocket events are tracked:
class ChatChannel < ApplicationCable::Channel
  def subscribed
    BrainzLab::Recall.info("User subscribed to chat",
      channel: "ChatChannel",
      room_id: params[:room_id]
    )
  end
end

Rails Logger Replacement

Send all Rails logs to Recall with a single line:
# config/initializers/brainzlab.rb
BrainzLab.configure do |config|
  config.secret_key = ENV['BRAINZLAB_SECRET_KEY']
end

# Option 1: Replace Rails.logger entirely
Rails.logger = BrainzLab.logger

# Option 2: Keep console output AND send to Recall
Rails.logger = BrainzLab.logger(broadcast_to: Rails.logger)
Now all Rails logs go to Recall:
Rails.logger.info("User signed in")
Rails.logger.error("Payment failed")
Rails.logger.debug("Cache hit for key: user_123")
The logger supports all standard Rails features:
# Tagged logging
Rails.logger.tagged("RequestID-123") do
  Rails.logger.info("Processing request")
end

# Silencing logs
Rails.logger.silence do
  noisy_operation
end

View Instrumentation

Track view rendering:
BrainzLab.configure do |config|
  config.recall_instrument_views = true
end

# Logs view render times
# render users/show.html.erb (45.2ms)

Middleware

The SDK adds middleware automatically:
  1. BrainzLab::Rails::Middleware - Captures request context, breadcrumbs, and clears context after request
The middleware captures:
  • Request ID
  • Session ID (if loaded)
  • Request method, path, URL
  • Filtered request parameters
  • Request headers (excluding Cookie and Authorization)

Zero-Configuration Error Tracking

The SDK provides “nothing to do” error tracking. Just install the gem and configure your API key:
# config/initializers/brainzlab.rb
BrainzLab.configure do |config|
  config.secret_key = ENV['BRAINZLAB_SECRET_KEY']
end
Errors are automatically captured from:
SourceWhat’s Captured
ControllersAll unhandled exceptions with request context
ActiveJobJob failures with job class, ID, queue, arguments
SidekiqJob failures with retry count and job metadata
Rails.errorAll errors reported via Rails 7+ error reporter

Disable Automatic Capture

To disable automatic capture in specific environments:
# config/environments/test.rb
BrainzLab.configure do |config|
  config.reflex_enabled = false
end

Pulse APM Integration

Pulse provides automatic performance monitoring for Rails applications.

Request Tracing

Every request is automatically traced with detailed timing breakdown:
GET /orders/123 (250ms)
├── OrdersController#show (248ms)
│   ├── SQL: SELECT * FROM orders (5ms)
│   ├── SQL: SELECT * FROM users (3ms)
│   ├── HTTP: GET api.stripe.com/charges (150ms)
│   └── View: orders/show.html.erb (80ms)
│       ├── Partial: _line_items (40ms)
│       └── Partial: _summary (30ms)

Automatic Instrumentation

Pulse automatically instruments these Rails components:
ComponentWhat’s Tracked
Rack/RailsRequest method, path, status, timing
Active RecordSQL queries with duration
ActionViewTemplate and partial rendering
ActionMailerEmail delivery time
ActiveJobJob execution time
Net::HTTPOutbound HTTP requests

Configuration

BrainzLab.configure do |config|
  config.pulse_enabled = true
  config.pulse_sample_rate = 1.0  # 100% of requests

  # Exclude health check endpoints
  config.pulse_excluded_paths = ['/health', '/ping', '/up', '/assets']
end

Distributed Tracing

Pulse propagates trace context across services:
# In your controller - starts a trace
def create
  @order = Order.create!(params)
  ProcessOrderJob.perform_async(@order.id)  # Trace context passed to job
end

# In Sidekiq job - continues the same trace
class ProcessOrderJob
  include Sidekiq::Job

  def perform(order_id)
    # This job is linked to the original web request trace
    order = Order.find(order_id)
    order.process!
  end
end

Custom Spans

Add custom spans for business logic:
def calculate_pricing
  BrainzLab::Pulse.trace("pricing.calculate", kind: "business") do |span|
    span[:data] = {
      product_count: @cart.items.count,
      has_discount: @cart.discount.present?
    }

    PricingEngine.calculate(@cart)
  end
end
See Pulse documentation for more details.