You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby on Rails+Grape应用全局记录所有异常至Sentry等APM的最佳方法

全局记录Rails + Grape应用所有异常的最佳方案

一、Rails 应用全局异常捕获配置

核心思路是覆盖Rails的异常处理链路,同时兼容原有业务逻辑,确保所有捕获/未捕获异常都能被APM工具记录。

1. 全局rescue_from捕获控制器异常

在ApplicationController中配置层级化的异常处理,先保留业务自定义的异常处理规则,最后兜底捕获所有未覆盖的异常并上报:

class ApplicationController < ActionController::Base
  # 保留原有业务的异常处理规则
  rescue_from ActiveRecord::RecordNotFound, with: :handle_not_found

  # 兜底捕获所有未被处理的异常
  rescue_from StandardError do |e|
    # 执行原有业务错误处理逻辑
    handle_generic_error(e)
    # 上报至APM工具(以Sentry为例,其他工具替换对应方法)
    Sentry.capture_exception(e)
    # 如需重新抛出异常,保留该语句
    raise e
  end

  private

  def handle_not_found
    render json: { error: "资源不存在" }, status: :not_found
    # 上报原本视为"无关注价值"的404异常
    Sentry.capture_exception(ActiveRecord::RecordNotFound.new)
  end

  def handle_generic_error(e)
    render json: { error: e.message }, status: :internal_server_error
  end
end

可选过滤:如果仍需排除极少数异常,可在上报前添加判断:

unless e.is_a?(完全无需记录的异常类)
  Sentry.capture_exception(e)
end

2. 利用Rails事件订阅器捕获底层异常

通过ActiveSupport::Notifications订阅控制器事件,能捕获所有控制器层面的异常(包括手动rescue的):

# 在config/initializers/apm_exception_subscriber.rb中添加
ActiveSupport::Notifications.subscribe("process_action.action_controller") do |*args|
  event = ActiveSupport::Notifications::Event.new(*args)
  exception = event.payload[:exception_object]
  Sentry.capture_exception(exception) if exception
end

该方案无需修改业务代码,适合全量采集控制器范围内的所有异常。

二、Grape 应用全局异常捕获配置

Grape有独立的异常处理机制,需针对其请求生命周期单独配置。

1. 全局rescue_from覆盖API异常

在Grape的API基类中配置层级化异常处理,确保所有API请求的异常都被捕获上报:

class API < Grape::API
  format :json

  # 保留原有业务的校验异常处理
  rescue_from Grape::Exceptions::ValidationErrors, with: :handle_validation_errors

  # 兜底捕获所有未被处理的异常
  rescue_from StandardError do |e|
    handle_api_error(e)
    # 上报至APM工具
    Sentry.capture_exception(e)
    # 如需重新抛出,保留该语句
    raise e
  end

  private

  def handle_validation_errors(e)
    error!(e.message, 400)
    # 上报原本视为"无关注价值"的参数校验异常
    Sentry.capture_exception(e)
  end

  def handle_api_error(e)
    error!({ error: e.message }, 500)
  end
end

2. 利用Grape中间件拦截全局异常

通过Grape的错误中间件,捕获请求生命周期内的所有异常(包括路由匹配、参数解析阶段):

# 在config/initializers/grape.rb中配置
Grape::Middleware::Error.before do |e|
  # 上报异常
  Sentry.capture_exception(e)
  # 继续执行原有错误处理逻辑
  throw :error, e
end

三、跨APM工具适配方案

不同APM工具的上报方法只需简单替换,核心逻辑一致:

  • Sentry: Sentry.capture_exception(e)
  • Honeybadger: Honeybadger.notify(e)
  • NewRelic: NewRelic::Agent.notice_error(e)
  • SignalFx: 参考对应SDK的错误上报方法(如SignalFx::Client.new.report_error(e))

四、避免重复上报的注意事项

  • 若同时配置Rails和Grape的全局捕获,可能出现重复上报,可通过标记异常解决:
    # Grape中上报时标记
    rescue_from StandardError do |e|
      e.instance_variable_set(:@reported_to_apm, true)
      Sentry.capture_exception(e)
      handle_api_error(e)
    end
    
    # Rails中跳过已标记的异常
    rescue_from StandardError do |e|
      Sentry.capture_exception(e) unless e.instance_variable_get(:@reported_to_apm)
      handle_generic_error(e)
    end
    
  • 手动rescue的代码块,建议封装统一工具方法替代原生rescue,确保异常被上报:
    def rescue_and_report(exception_class = StandardError)
      yield
    rescue exception_class => e
      Sentry.capture_exception(e)
      # 执行原有业务处理逻辑
      handle_custom_error(e)
      # 按需重新抛出
      raise e
    end
    
    # 业务代码中使用
    rescue_and_report(ActiveRecord::RecordInvalid) do
      # 业务逻辑
    end
    

内容的提问来源于stack exchange,提问作者David Hempy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 13:13:10