Ruby China 很早以前就基于 exception_notification 实现了线上应用异常捕捉功能,并将捕捉到的错误信息存储到数据库里面,以便于可以在后台查看。
实际上 exception_notification 感觉是推荐用通知的方式(Email, Slack, WebHook ...)
但根据我这几年长期使用来看,通知会变成“狼来了”,因为一些异常我们不可能完全修复:
这些,我们可以需要记录下来,对整个系统的线上状况有清晰的认识,但不能发通知。
所以 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 的界面了(当然没数据,你需要故意制造点异常出来)
默认情况下,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 的基础配置那一套,也不用自己实现一个界面(虽然实现成本不高,但我不想再另外一个项目里面重做一次相同的事情)。
而据我的使用情况来看,绝大多数项目有这么个简简单单的界面,就够了,你只需要做的是,定期查阅异常列表,尽可能的修复它们,然后清空列表(往后反复重复这个动作)