Gem ExceptionTrack - 捕捉 Rails 应用运行期的异常,并存储到数据库

huacnlee for Rails Engine Gem · 发布于 2017年2月17日 · 最后由 femto 回复于 2017年3月23日 · 2394 次阅读
2
本帖已被设为精华帖!

Ruby China 很早以前就基于 exception_notification 实现了线上应用异常捕捉功能,并将捕捉到的错误信息存储到数据库里面,以便于可以在后台查看。

实际上 exception_notification 感觉是推荐用通知的方式(Email, Slack, WebHook ...)

但根据我这几年长期使用来看,通知会变成“狼来了”,因为一些异常我们不可能完全修复:

  • 有时候异常是由于恶意的扫描程序(但不影响)带来的;
  • 已知,但不好修复,或暂时无法修复的异常,或不影响使用且不好修复的异常;
  • 网络 IO 导致的偶发性异常,例如请求一个 GitHub 的地址,邮件发送失败;
  • ... 其他一些不影响系统运作的非核心功能异常;

这些,我们可以需要记录下来,对整个系统的线上状况有清晰的认识,但不能发通知。

所以 Ruby China 将异常信息存放倒数据库里面,并在管理后台做了个界面可以供我时不时的查阅。


基于上面的实践经验,我将它做成了 Gem,以方便其他项目也可以这么做。

安装

gem 'exception-track'

然后

$ bundle install

并执行 exception_track:install 生成配置文件和 Migration 文件

$ rails g exception_track:install
# 然后合并数据库
$ rails db:migrate

修改 routes.rb

Rails.application.routes.draw do
  mount ExceptionTrack::Engine => "/exception-track"
end

一般我们可能会让这个功能仅管理员可用,那么你可以这么做:

# lib/admin_constraint.rb
class AdminConstraint
  def matches?(request)
    return false if !request.session[:user_id]
    user = User.find(request.session[:user_id])
    user && user.admin?
  end
end

# config/router.rb
require 'admin_constraint'
mount ExceptionTrack::Engine => "/exception-track", constraints: AdminConstraint.new

如果是 Devise 的话,可以这么干来限制权限

Rails.application.routes.draw do
  authenticate :user, ->(u) { u.admin? } do
    mount ExceptionTrack::Engine => "/exception-track"
  end
end

然后你就可以访问 http://localhost:3000/exception-track 查看 ExceptionTrack 的界面了(当然没数据,你需要故意制造点异常出来)

配置只在 production 环境才记录异常到数据库

默认情况下, ExceptionTrack 在 development, production 两个环境下将异常写入到数据库,如果你不希望 development 写信息(因为 rails console 已经能看到了,默认那样是为了演示),你可以调整一下配置:

config/initializers/exception-track.rb

ExceptionTrack.configure do
  self.environments = %i(production)
end

# 同时,你还可以在这个文件配置 ExceptionNotification
require 'exception_notification/sidekiq'
ExceptionNotification.configure do |config|
  # ignored_exceptions 是 Ruby China 的配置,可以参考一下
  config.ignored_exceptions += %w(ActionView::TemplateError
                                  ActionController::InvalidAuthenticityToken
                                  ActionController::BadRequest
                                  ActionView::MissingTemplate
                                  ActionController::UrlGenerationError
                                  ActionController::UnknownFormat)
end

关于 ExceptionNotification 的更多配置,请详细阅读 ExceptionNotification 的文档

实现理念

这是一个简单而实用的东西,目的是为了一般性的项目不再反复搞 ExceptionNotification 的基础配置那一套,也不用自己实现一个界面(虽然实现成本不高,但我不想再另外一个项目里面重做一次相同的事情)。

而据我的使用情况来看,绝大多数项目有这么个简简单单的界面,就够了,你只需要做的是,定期查阅异常列表,尽可能的修复它们,然后清空列表(往后反复重复这个动作)

项目地址

https://github.com/rails-engine/exception-track

共收到 13 条回复
13587

我们用rollbar,不过还是给个赞

3 lgn21st 将本帖设为了精华贴 2月19日 00:29
24422

我用exception_notification 过滤不必要的异常邮件的发送,现在有这个Gem还是挺方便的,比查看错误邮件方便多了

1181

@huacnlee 这么好的东西从Rails 4.2开始支持的啊,能从Rails 4.0开始支持吗? 😆

2

#4楼 @lifuzho 不知道能不能用,精力有限,要保持向下兼容需要费神一些。 😪 😶

先把 gemspec 调整一下,你用用看,版本 0.1.3

2329

搭便车也推荐个我写的小工具: rails_log

同时也支持邮件日志。

没有其他依赖,用的是 Notifications 和 Subscriber 的机制实现的,不是有些gem用的rescue_from,性能更好(因为Rails的Notifications/Subscriber 是在另启的线程里完成的)。

效果图如下:

可以在配置文件里配置 权限 和 不通知的异常,如:

RailsLog.configure do |config|
  config.ignore_exception = [
    'ActionController::UnknownFormat'
  ]

  # 默认配置也是会判断 admin? 为 true
  config.constraint = -> (req){ Employee.find_by(id: req.env['rack.session']['warden.user.employee.key'][0][0])&.admin? }
end

用法也很简单,直接添加到gem 里面,然后跑下migrations 就可以了。

——————

更正:有依赖,依赖自己写的一个 通用engine, rails_com , 抽时间把依赖加上。或者fork后自己改一下。

96

sentry 才是标配吧

1181

@huacnlee 改了 gemspec 之后确实可以用了, 不过 will_paginatekaminari 有冲突 😂

2

#8楼 @lifuzho 不冲突,可以同时用的,我才尝试过。

1090

谢谢分享。

ps: 我们把登录用户的log也保存到数据库里的😄

19106

能像airbrake那样手动抛异常么?

2
19106yingce 回复

Ruby 直接抛异常就可以了呀

19106
2huacnlee 回复

也对 自定义几个异常就行了 哈哈

96

@huacnlee 有没有像HoneyBadger或者NewRelic一样,手动调记录异常的? (因为有时候我们业务会自己捕获异常做一些处理), 类似于 HoneyBadger.notify_exception(e) NewRelic::Agent.notice_error(e)

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册