Files
2025-12-01 15:59:26 +11:00

156 lines
4.9 KiB
Ruby

# frozen_string_literal: true
# Sentry configuration for error tracking and performance monitoring
# Only initializes if SENTRY_DSN is configured
return unless ENV['SENTRY_DSN'].present?
require 'sentry-rails'
Sentry.init do |config|
config.dsn = ENV['SENTRY_DSN']
# Configure sampling for production (lower in production, higher in staging)
config.traces_sample_rate = case Rails.env
when 'production' then ENV.fetch('SENTRY_TRACES_SAMPLE_RATE', '0.05').to_f
when 'staging' then ENV.fetch('SENTRY_TRACES_SAMPLE_RATE', '0.2').to_f
else ENV.fetch('SENTRY_TRACES_SAMPLE_RATE', '0.1').to_f
end
# Enable breadcrumbs for better debugging
config.breadcrumbs_logger = [:active_support_logger, :http_logger]
# Send PII data (like IPs) to Sentry for debugging (disable in production if needed)
config.send_default_pii = ENV.fetch('SENTRY_SEND_PII', 'false') == 'true'
# Set environment
config.environment = Rails.env
# Configure release info from Docker tag or Git
if ENV['GIT_COMMIT_SHA']
config.release = ENV['GIT_COMMIT_SHA'][0..7]
elsif ENV['APP_VERSION']
config.release = ENV['APP_VERSION']
end
# Set server name for multi-instance environments
config.server_name = ENV.fetch('SERVER_NAME', 'baffle-agent')
# Filter out certain errors to reduce noise and add tags
config.before_send = lambda do |event, hint|
# Filter out 404 errors and other expected HTTP errors
if event.contexts.dig(:response, :status_code) == 404
nil
# Filter out validation errors in development
elsif Rails.env.development? && event.exception&.message&.include?("Validation failed")
nil
# Filter out specific noisy exceptions
elsif %w[ActionController::RoutingError
ActionController::InvalidAuthenticityToken
ActionController::UnknownFormat
ActionDispatch::Http::Parameters::ParseError].include?(event.exception&.class&.name)
nil
else
# Add tags for better filtering in Sentry
event.tags.merge!({
ruby_version: RUBY_VERSION,
rails_version: Rails.version,
environment: Rails.env
})
event
end
end
# Configure exception class exclusion
config.excluded_exceptions += [
'ActionController::RoutingError',
'ActionController::InvalidAuthenticityToken',
'CGI::Session::CookieStore::TamperedWithCookie',
'ActionController::UnknownFormat',
'ActionDispatch::Http::Parameters::ParseError',
'Mongoid::Errors::DocumentNotFound'
]
end
# SolidQueue monitoring will be automatically handled by sentry-solid_queue gem
# Add correlation ID to Sentry context
ActiveSupport::Notifications.subscribe('action_controller.process_action') do |name, start, finish, id, payload|
controller = payload[:controller]
action = payload[:action]
request_id = payload[:request]&.request_id
if controller && action && request_id
Sentry.set_context(:request, {
correlation_id: request_id,
controller: controller.controller_name,
action: action.action_name,
ip: request&.remote_ip
})
end
end
# Add ActiveJob context to all job transactions
ActiveSupport::Notifications.subscribe('perform.active_job') do |name, start, finish, id, payload|
job = payload[:job]
Sentry.configure_scope do |scope|
scope.set_tag(:job_class, job.class.name)
scope.set_tag(:job_queue, job.queue_name)
scope.set_tag(:job_id, job.job_id)
scope.set_context(:job, {
job_id: job.job_id,
job_class: job.class.name,
queue_name: job.queue_name,
arguments: job.arguments.to_s,
enqueued_at: job.enqueued_at,
executions: job.executions
})
end
end
# Monitor SolidQueue job failures
ActiveSupport::Notifications.subscribe('solid_queue.error') do |name, start, finish, id, payload|
job = payload[:job]
error = payload[:error]
Sentry.with_scope do |scope|
scope.set_tag(:job_class, job.class_name)
scope.set_tag(:job_queue, job.queue_name)
scope.set_context(:job, {
job_id: job.active_job_id,
arguments: job.arguments.to_s,
queue_name: job.queue_name,
created_at: job.created_at
})
scope.set_context(:error, {
error_class: error.class.name,
error_message: error.message
})
Sentry.capture_exception(error)
end
end
# Set user context when available
if defined?(Current) && Current.user
Sentry.set_user(id: Current.user.id, email: Current.user.email)
end
# Add application-specific context
app_version = begin
BaffleHub::VERSION
rescue
ENV['APP_VERSION'] || ENV['GIT_COMMIT_SHA']&.[](0..7) || 'unknown'
end
Sentry.set_context('application', {
name: 'BaffleHub',
version: app_version,
environment: Rails.env,
database: ActiveRecord::Base.connection.adapter_name,
queue_adapter: Rails.application.config.active_job.queue_adapter
})
Rails.logger.info "Sentry configured for environment: #{Rails.env}"