Skip to content

Latest commit

 

History

History
357 lines (282 loc) · 7.09 KB

File metadata and controls

357 lines (282 loc) · 7.09 KB

Ruby Integration

Complete setup for Rails, Sinatra, and standalone Ruby applications.

Gem Installation

# Gemfile
gem 'honeybadger'
gem 'sentry-ruby'
gem 'sentry-rails' # For Rails
gem 'devcycle-ruby-server-sdk'
gem 'appwrite'
bundle install

Rails Setup

config/initializers/sentry.rb

Sentry.init do |config|
  config.dsn = ENV['SENTRY_DSN']
  config.environment = Rails.env
  config.traces_sample_rate = 0.1
  config.breadcrumbs_logger = [:active_support_logger, :http_logger]
end

config/initializers/honeybadger.rb

# Or run: bundle exec honeybadger install [API_KEY]
Honeybadger.configure do |config|
  config.api_key = ENV['HONEYBADGER_API_KEY']
  config.env = Rails.env
end

config/initializers/devcycle.rb

require 'devcycle-ruby-server-sdk'

$devcycle_client = DevCycle::Client.new(
  ENV['DEVCYCLE_SERVER_SDK_KEY'],
  DevCycle::Options.new(enable_cloud_bucketing: true)
)

config/initializers/appwrite.rb

require 'appwrite'

$appwrite_client = Appwrite::Client.new
  .set_endpoint(ENV['APPWRITE_ENDPOINT'])
  .set_project(ENV['APPWRITE_PROJECT_ID'])
  .set_key(ENV['APPWRITE_API_KEY'])

$appwrite_databases = Appwrite::Databases.new($appwrite_client)

Services Module

app/services/monitoring.rb

module Monitoring
  class << self
    def capture_error(error, context = {})
      # Log locally
      Rails.logger.error("#{error.class}: #{error.message}")
      Rails.logger.error(error.backtrace.join("\n")) if error.backtrace

      # Report to Sentry
      Sentry.capture_exception(error, extra: context)

      # Report critical errors to Honeybadger
      if error.respond_to?(:critical?) && error.critical?
        Honeybadger.notify(error, context: context)
      end
    end

    def capture_message(message, level: :info, context: {})
      Sentry.capture_message(message, level: level, extra: context)
    end
  end
end

# Usage in controllers
class ApplicationController < ActionController::Base
  rescue_from StandardError do |exception|
    Monitoring.capture_error(exception, {
      user_id: current_user&.id,
      path: request.path
    })
    raise exception
  end
end

Feature Flags

app/services/feature_flags.rb

module FeatureFlags
  class << self
    def enabled?(user, flag_key, default: false)
      devcycle_user = DevCycle::User.new(user_id: user.id.to_s)
      $devcycle_client.variable_value(devcycle_user, flag_key, default)
    rescue => e
      Monitoring.capture_error(e, { flag_key: flag_key })
      default
    end

    def get_value(user, flag_key, default)
      devcycle_user = DevCycle::User.new(
        user_id: user.id.to_s,
        email: user.email,
        custom_data: { plan: user.plan }
      )
      $devcycle_client.variable_value(devcycle_user, flag_key, default)
    rescue => e
      Monitoring.capture_error(e, { flag_key: flag_key })
      default
    end
  end
end

# Usage in controllers
class CheckoutController < ApplicationController
  def show
    if FeatureFlags.enabled?(current_user, 'new-checkout')
      render :new_checkout
    else
      render :legacy_checkout
    end
  end
end

# Usage in views
<% if FeatureFlags.enabled?(current_user, 'show-banner') %>
  <%= render 'banner' %>
<% end %>

Appwrite Service

app/services/appwrite_service.rb

module AppwriteService
  class << self
    def create_document(database_id, collection_id, data)
      $appwrite_databases.create_document(
        database_id: database_id,
        collection_id: collection_id,
        document_id: Appwrite::ID.unique,
        data: data
      )
    end

    def list_documents(database_id, collection_id, queries: [])
      $appwrite_databases.list_documents(
        database_id: database_id,
        collection_id: collection_id,
        queries: queries
      )
    end

    def get_document(database_id, collection_id, document_id)
      $appwrite_databases.get_document(
        database_id: database_id,
        collection_id: collection_id,
        document_id: document_id
      )
    end
  end
end

# Usage
AppwriteService.create_document('main', 'users', {
  name: 'John',
  email: 'john@example.com'
})

Sinatra Setup

app.rb

require 'sinatra'
require 'sentry-ruby'
require 'honeybadger'

Sentry.init do |config|
  config.dsn = ENV['SENTRY_DSN']
end

Honeybadger.configure do |config|
  config.api_key = ENV['HONEYBADGER_API_KEY']
end

use Sentry::Rack::CaptureExceptions

error do
  error = env['sinatra.error']
  Honeybadger.notify(error)
  'Something went wrong'
end

get '/' do
  'Hello World'
end

Background Jobs (Sidekiq)

config/initializers/sidekiq.rb

Sidekiq.configure_server do |config|
  config.error_handlers << proc { |ex, ctx_hash|
    Sentry.capture_exception(ex, extra: ctx_hash)
    Honeybadger.notify(ex, context: ctx_hash)
  }
end

app/jobs/example_job.rb

class ExampleJob
  include Sidekiq::Job

  def perform(user_id)
    user = User.find(user_id)

    # Add context for error tracking
    Sentry.set_user(id: user.id, email: user.email)
    Honeybadger.context(user_id: user.id)

    # Your job logic
    do_work(user)
  rescue => e
    Monitoring.capture_error(e, { user_id: user_id })
    raise
  end
end

Environment Variables

# .env

# Sentry
SENTRY_DSN=https://key@sentry.io/project

# Honeybadger
HONEYBADGER_API_KEY=your_key

# DevCycle
DEVCYCLE_SERVER_SDK_KEY=server_key

# Appwrite
APPWRITE_ENDPOINT=https://cloud.appwrite.io/v1
APPWRITE_PROJECT_ID=your_project
APPWRITE_API_KEY=your_api_key

Testing

spec/services/feature_flags_spec.rb

require 'rails_helper'

RSpec.describe FeatureFlags do
  let(:user) { create(:user) }

  before do
    allow($devcycle_client).to receive(:variable_value).and_return(true)
  end

  describe '.enabled?' do
    it 'returns the flag value' do
      expect(described_class.enabled?(user, 'new-feature')).to be true
    end

    it 'returns default on error' do
      allow($devcycle_client).to receive(:variable_value).and_raise(StandardError)

      expect(described_class.enabled?(user, 'new-feature', default: false)).to be false
    end
  end
end

spec/support/monitoring_helper.rb

RSpec.configure do |config|
  config.before(:each) do
    allow(Sentry).to receive(:capture_exception)
    allow(Honeybadger).to receive(:notify)
  end
end

Rake Tasks

lib/tasks/monitoring.rake

namespace :monitoring do
  desc 'Test Sentry connection'
  task test_sentry: :environment do
    Sentry.capture_message('Test message from rake task')
    puts 'Sentry test message sent'
  end

  desc 'Test Honeybadger connection'
  task test_honeybadger: :environment do
    Honeybadger.notify(StandardError.new('Test error from rake task'))
    puts 'Honeybadger test error sent'
  end
end

Check-ins for Cron Jobs

lib/tasks/scheduled.rake

namespace :scheduled do
  desc 'Daily cleanup task'
  task cleanup: :environment do
    # Start check-in
    Honeybadger.check_in('daily-cleanup')

    begin
      # Your task logic
      cleanup_old_records
    rescue => e
      Monitoring.capture_error(e)
      raise
    end
  end
end