git://www.github.com/flyerhzm/bullet.git
git clone http://www.github.com/flyerhzm/bullet
$ svn co --depth empty http://www.github.com/flyerhzm/bullet
Checked out revision 1.
$ cd repo
$ svn up trunk
项目符号 gem 旨在帮助你通过减少查询的数量来提高应用程序的性能。 如果你正在开发应用程序,并且在你使用非必需加载时通知你,当你使用非必需加载时,当你使用计数器缓存时,就会看到你的查询。
最佳实践是在开发模式或者定制模式( 分级,配置文件,等等 ) 中使用项目符号。 你最不想看到的是你的客户收到关于懒惰的通知。
项目符号 gem 现在支持英镑 activerecord> = 4.0和英镑 mongoid> = 4.0.
如果你使用 activerecord,请使用 bullet = 4.5.0
如果你使用 activerecord,请使用项目符号 <。
你可以将它的安装为 gem:
gem install bullet
或者将它添加到 Gemfile ( Bundler ):
gem 'bullet', group:'development'
英镑注释: 确保在 activerecord ( Rails ) 和mongoid之后添加了 bullet
。
子弹不会做任何事情除非你告诉它。 使用以下代码附加到 config/environments/development.rb
初始值设定项:
config.after_initialize doBullet.enable =trueBullet.sentry =trueBullet.alert =trueBullet.bullet_logger =trueBullet.console =trueBullet.growl =trueBullet.xmpp = { :account => 'bullets_account@jabber.org', :password => 'bullets_password_for_jabber', :receiver => 'your_account@jabber.org', :show_online_status => true } Bullet.rails_logger =trueBullet.honeybadger =trueBullet.bugsnag =trueBullet.airbrake =trueBullet.rollbar =trueBullet.add_footer =trueBullet.stacktrace_includes = [ 'your_gem', 'your_middleware' ] Bullet.stacktrace_excludes = [ 'their_gem', 'their_middleware' ] Bullet.slack = { webhook_url:'http://some.slack.url', channel:'#default', username:'notifier' }end
子弹的通知者是一个包裹的 uniform_notifier 。
代码 above 将启用所有项目符号通知系统:
Bullet.enable
: 启用项目符号 gem,否则不执行任何操作Bullet.alert
: 在浏览器中弹出一个JavaScript警告Bullet.bullet_logger
: 登录到项目符号日志文件 (Rails.root/log/bullet.log)Bullet.console
: 将警告记录到浏览器的console.log ( safari/webkit 浏览器或者 Firefox w/firebug安装)Bullet.growl
: 如果你的系统已经安装了咆哮,则弹出咆哮警告。 需要一些配置Bullet.xmpp
: 向接收方发送 xmpp/jabber通知。 注意,代码当前不处理联系人添加,因这里你需要在接收到任何通知之前手动使两个帐户相互识别。 在这里示例中,项目符号帐户的'正在联机'声音可能会开始 annoy - 在这里情况下,设置为:show_online_status到 false,但项目符号帐户不会显示,但项目符号帐户将不再显示为在线状态。Bullet.rails_logger
: 直接向 Rails 日志添加警告Bullet.honeybadger
: 向Honeybadger添加通知Bullet.bugsnag
: 向Bugsnag添加通知Bullet.airbrake
: 向airbrake添加通知Bullet.rollbar
: 向rollbar添加通知Bullet.sentry
: 向岗哨添加通知Bullet.add_footer
: 在页面的左下角添加细节。 双击页脚或者使用关闭按钮隐藏页脚。Bullet.stacktrace_includes
: 包括在堆栈跟踪中使用任何子字符串的路径,即使它们不在主应用程序中Bullet.stacktrace_excludes
: 忽略堆栈跟踪中任何子字符串的路径,即使它们不在主应用程序中。Bullet.slack
: 向松弛添加通知Bullet.raise
: 引发错误,用于使你的规范失败,除非它们有优化的查询Bullet还允许你禁用它的任何检测器。
# Each of these settings defaults to true# Detect N+1 queriesBullet.n_plus_one_query_enable =false# Detect eager-loaded associations which are not usedBullet.unused_eager_loading_enable =false# Detect unnecessary COUNT queries which could be avoided# with a counter_cacheBullet.counter_cache_enable =false
有时项目符号会通知你不需要修复的查询问题,或者来自你的代码之外的问题。 你可以对这些内容进行白名单,以忽略它们:
Bullet.add_whitelist :type => :n_plus_one_query, :class_name => "Post", :association => :commentsBullet.add_whitelist :type => :unused_eager_loading, :class_name => "Post", :association => :commentsBullet.add_whitelist :type => :counter_cache, :class_name => "Country", :association => :cities
如果你想在某些特定的控制器动作中跳过项目符号,你可以
classApplicationController <ActionController::Base around_action :skip_bulletdefskip_bulletBullet.enable =falseyieldensureBullet.enable =trueendend
项目符号日志 log/bullet.log
的外观如下所示:
2009-08-25 20:40:17[INFO] N+1 Query: PATH_INFO:/posts; model: Post => associations: [comments]·
Add to your finder: :include => [:comments]
2009-08-25 20:40:17[INFO] N+1 Query: method call stack:·
/Users/richard/Downloads/test/app/views/posts/index.html.erb:11:in `_run_erb_app47views47posts47index46html46erb'
/Users/richard/Downloads/test/app/views/posts/index.html.erb:8:in `each'
/Users/richard/Downloads/test/app/views/posts/index.html.erb:8:in `_run_erb_app47views47posts47index46html46erb'
/Users/richard/Downloads/test/app/controllers/posts_controller.rb:7:in `index'
前两行是N+1查询所遇到的通知。 其余行是堆栈跟踪,因此你可以准确地找到在代码中调用查询的位置,并修复它们。
2009-08-25 20:53:56[INFO] Unused eager loadings: PATH_INFO:/posts; model: Post => associations: [comments]·
Remove from your finder: :include => [:comments]
这两行是未使用的热切加载的通知。
2009-09-11 09:46:50[INFO] Need Counter Cache
Post => [:comments]
请参见 https://github.com/flyerhzm/uniform_notifier
如果发现项目符号无法为你工作,请禁用浏览器的缓存功能。
项目符号 gem 使用 rack 中间件来配置请求。 如果要使用不带http服务器的项目符号,就像配置作业一样,可以以使用配置文件方法和提示。
Bullet.profile do# do anything warnings =Bullet.warningsend
配置和使用 Bullet::Rack
configure :developmentdoBullet.enable =trueBullet.bullet_logger =true use Bullet::Rackend
首先,你需要在测试环境中启用项目符号。
# config/environments/test.rbconfig.after_initialize doBullet.enable =trueBullet.bullet_logger =trueBullet.raise=true# raise an error if n+1 query occursend
然后将每个测试包装为 Bullet 。
# spec/spec_helper.rbifBullet.enable? config.before(:each) doBullet.start_request end config.after(:each) doBullet.perform_out_of_channel_notifications ifBullet.notification? Bullet.end_request endend
项目符号输出一些详细信息信息,以启用调试模式,设置 BULLET_DEBUG=true
环境。
https://github.com/flyerhzm/bullet/contributors
项目符号设计为在开发中浏览应用程序时进行功能。 要查看实际操作,你可以访问 https://github.com/flyerhzm/bullet_test 插件,或者按照以下步骤创建。检测和修复示例查询问题。
1.创建示例应用程序
$ rails new test_bullet
$ cd test_bullet
$ rails g scaffold post name:string
$ rails g scaffold comment name:string post_id:integer
$ bundle exec rake db:migrate
2.更改 app/model/post.rb
和 app/model/comment.rb
classPost <ActiveRecord::Base has_many :commentsendclassComment <ActiveRecord::Base belongs_to :postend
3 。转到 rails c
并执行
post1 =Post.create(:name => 'first') post2 =Post.create(:name => 'second') post1.comments.create(:name => 'first') post1.comments.create(:name => 'second') post2.comments.create(:name => 'third') post2.comments.create(:name => 'fourth')
4.更改 app/views/posts/index.html.erb
以生成N+1查询
<% @posts.each do |post| %>
<tr>
<td><%= post.name %></td>
<td><%= post.comments.map(&:name) %></td>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
5.将 bullet
gem 添加到 Gemfile
gem "bullet"
并运行
bundle install
6.启用带有生成命令的项目符号 gem
bundle exec rails g bullet:install
7.启动服务器
$ rails s
8.在浏览器中访问 http://localhost:3000/posts
,你将看到一个弹出式警报框
The request has unused preload associations as follows:
None
The request has N+1 queries as follows:
model: Post => associations: [comment]
这意味着Post对象中有一个N+1查询到它的评论关联。
同时,在 log/bullet.log
文件中添加了一个日志
2010-03-07 14:12:18[INFO] N+1 Query in/posts
Post => [:comments]
Add to your finder: :include => [:comments]
2010-03-07 14:12:18[INFO] N+1 Query method call stack
/home/flyerhzm/Downloads/test_bullet/app/views/posts/index.html.erb:14:in `_render_template__600522146_80203160_0'
/home/flyerhzm/Downloads/test_bullet/app/views/posts/index.html.erb:11:in `each'
/home/flyerhzm/Downloads/test_bullet/app/views/posts/index.html.erb:11:in `_render_template__600522146_80203160_0'
/home/flyerhzm/Downloads/test_bullet/app/controllers/posts_controller.rb:7:in `index'
生成的SQL是:
Post Load (1.0ms) SELECT * FROM"posts"
Comment Load (0.4ms) SELECT * FROM"comments" WHERE ("comments".post_id = 1)
Comment Load (0.3ms) SELECT * FROM"comments" WHERE ("comments".post_id = 2)
9.要修复N+1查询,请更改 app/controllers/posts_controller.rb
文件
defindex@posts=Post.includes(:comments) respond_to do |format| format.html # index.html.erbformat.xml { render :xml => @posts } endend
10.刷新 http://localhost:3000/posts
现在没有警告框,日志中没有新内容。
生成的SQL是:
Post Load (0.5ms) SELECT * FROM"posts"
Comment Load (0.5ms) SELECT"comments".* FROM"comments" WHERE ("comments".post_id IN (1,2))
N+1查询已经修复。Cool !
11.现在模拟未使用的立即加载。 更改 app/controllers/posts_controller.rb
还有 app/views/posts/index.html.erb
defindex@posts=Post.includes(:comments) respond_to do |format| format.html # index.html.erbformat.xml { render :xml => @posts } endend
<% @posts.each do |post| %>
<tr>
<td><%= post.name %></td>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
12.刷新 http://localhost:3000/posts
,你将看到一个弹出式警报框
The request has unused preload associations as follows:
model: Post => associations: [comment]
The request has N+1 queries as follows:
None
同时,在 log/bullet.log
中有一条行
2009-08-25 21:13:22[INFO] Unused preload associations: PATH_INFO:/posts; model: Post => associations: [comments]·
Remove from your finder: :include => [:comments]
13.模拟 counter_cache 。更改 app/controllers/posts_controller.rb
还有 app/views/posts/index.html.erb
defindex@posts=Post.all respond_to do |format| format.html # index.html.erbformat.xml { render :xml => @posts } endend
<% @posts.each do |post| %>
<tr>
<td><%= post.name %></td>
<td><%= post.comments.size %></td>
<td><%= link_to 'Show', post %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
14.刷新 http://localhost:3000/posts
,然后你将看到一个弹出式警报框
Need counter cache
Post => [:comments]
同时,在 log/bullet.log
中有一条行
2009-09-11 10:07:10[INFO] Need Counter Cache
Post => [:comments]
版权所有( c ) 2009 - 2016 Richard ( flyerhzm@gmail.com ),在MIT许可下发布