Commit 258cf879520c2496acf8123c1c795920275bd7b6
Exists in
master
and in
1 other branch
Merge pull request #113 from martinciu/performance_tweaks
Performance tweaks
Showing
43 changed files
with
616 additions
and
75 deletions
Show diff stats
.gitignore
| @@ -2,10 +2,12 @@ | @@ -2,10 +2,12 @@ | ||
| 2 | db/*.sqlite3 | 2 | db/*.sqlite3 |
| 3 | log/*.log | 3 | log/*.log |
| 4 | tmp/**/* | 4 | tmp/**/* |
| 5 | +tmp/* | ||
| 5 | config/config.yml | 6 | config/config.yml |
| 6 | config/deploy.rb | 7 | config/deploy.rb |
| 7 | config/deploy | 8 | config/deploy |
| 8 | config/mongoid.yml | 9 | config/mongoid.yml |
| 10 | +config/newrelic.yml | ||
| 9 | .rvmrc | 11 | .rvmrc |
| 10 | *~ | 12 | *~ |
| 11 | *.rbc | 13 | *.rbc |
Gemfile
| @@ -4,7 +4,6 @@ gem 'rails', '3.0.10' | @@ -4,7 +4,6 @@ gem 'rails', '3.0.10' | ||
| 4 | gem 'nokogiri' | 4 | gem 'nokogiri' |
| 5 | gem 'mongoid', '2.1.2' | 5 | gem 'mongoid', '2.1.2' |
| 6 | gem 'haml' | 6 | gem 'haml' |
| 7 | -gem 'will_paginate', '>=3' | ||
| 8 | gem 'htmlentities', "~> 4.3.0" | 7 | gem 'htmlentities', "~> 4.3.0" |
| 9 | gem 'devise', '~> 1.4.0' | 8 | gem 'devise', '~> 1.4.0' |
| 10 | gem 'lighthouse-api' | 9 | gem 'lighthouse-api' |
| @@ -18,6 +17,7 @@ gem 'inherited_resources' | @@ -18,6 +17,7 @@ gem 'inherited_resources' | ||
| 18 | gem 'SystemTimer', :platform => :ruby_18 | 17 | gem 'SystemTimer', :platform => :ruby_18 |
| 19 | gem 'hoptoad_notifier', "~> 2.4" | 18 | gem 'hoptoad_notifier', "~> 2.4" |
| 20 | gem 'actionmailer_inline_css', "~> 1.3.0" | 19 | gem 'actionmailer_inline_css', "~> 1.3.0" |
| 20 | +gem 'kaminari' | ||
| 21 | 21 | ||
| 22 | platform :ruby do | 22 | platform :ruby do |
| 23 | gem 'bson_ext', '~> 1.4.0' | 23 | gem 'bson_ext', '~> 1.4.0' |
| @@ -34,6 +34,7 @@ group :development, :test do | @@ -34,6 +34,7 @@ group :development, :test do | ||
| 34 | gem 'ruby-debug', :platform => :mri_18 | 34 | gem 'ruby-debug', :platform => :mri_18 |
| 35 | gem 'ruby-debug19', :platform => :mri_19, :require => 'ruby-debug' | 35 | gem 'ruby-debug19', :platform => :mri_19, :require => 'ruby-debug' |
| 36 | end | 36 | end |
| 37 | + gem 'rpm_contrib', :git => "git://github.com/bensymonds/rpm_contrib.git", :branch => "mongo-1.4.0_update" | ||
| 37 | end | 38 | end |
| 38 | 39 | ||
| 39 | group :test do | 40 | group :test do |
Gemfile.lock
| 1 | +GIT | ||
| 2 | + remote: git://github.com/bensymonds/rpm_contrib.git | ||
| 3 | + revision: 84ee78da6d0f154468d47c9e1e6597997e157291 | ||
| 4 | + branch: mongo-1.4.0_update | ||
| 5 | + specs: | ||
| 6 | + rpm_contrib (2.1.6.beta1) | ||
| 7 | + newrelic_rpm (>= 3.1.1) | ||
| 8 | + newrelic_rpm (>= 3.1.1) | ||
| 9 | + | ||
| 1 | GEM | 10 | GEM |
| 2 | remote: http://rubygems.org/ | 11 | remote: http://rubygems.org/ |
| 3 | specs: | 12 | specs: |
| @@ -80,6 +89,8 @@ GEM | @@ -80,6 +89,8 @@ GEM | ||
| 80 | inherited_resources (1.3.0) | 89 | inherited_resources (1.3.0) |
| 81 | has_scope (~> 0.5.0) | 90 | has_scope (~> 0.5.0) |
| 82 | responders (~> 0.6.0) | 91 | responders (~> 0.6.0) |
| 92 | + kaminari (0.12.4) | ||
| 93 | + rails (>= 3.0.0) | ||
| 83 | libxml-ruby (2.2.2) | 94 | libxml-ruby (2.2.2) |
| 84 | lighthouse-api (2.0) | 95 | lighthouse-api (2.0) |
| 85 | activeresource (>= 3.0.0) | 96 | activeresource (>= 3.0.0) |
| @@ -107,6 +118,7 @@ GEM | @@ -107,6 +118,7 @@ GEM | ||
| 107 | railties (>= 3.0.0) | 118 | railties (>= 3.0.0) |
| 108 | multi_json (1.0.3) | 119 | multi_json (1.0.3) |
| 109 | multipart-post (1.1.3) | 120 | multipart-post (1.1.3) |
| 121 | + newrelic_rpm (3.2.0) | ||
| 110 | nokogiri (1.5.0) | 122 | nokogiri (1.5.0) |
| 111 | octokit (0.6.4) | 123 | octokit (0.6.4) |
| 112 | addressable (~> 2.2.6) | 124 | addressable (~> 2.2.6) |
| @@ -205,7 +217,6 @@ GEM | @@ -205,7 +217,6 @@ GEM | ||
| 205 | webmock (1.7.6) | 217 | webmock (1.7.6) |
| 206 | addressable (~> 2.2, > 2.2.5) | 218 | addressable (~> 2.2, > 2.2.5) |
| 207 | crack (>= 0.1.7) | 219 | crack (>= 0.1.7) |
| 208 | - will_paginate (3.0.2) | ||
| 209 | 220 | ||
| 210 | PLATFORMS | 221 | PLATFORMS |
| 211 | ruby | 222 | ruby |
| @@ -223,6 +234,7 @@ DEPENDENCIES | @@ -223,6 +234,7 @@ DEPENDENCIES | ||
| 223 | hoptoad_notifier (~> 2.4) | 234 | hoptoad_notifier (~> 2.4) |
| 224 | htmlentities (~> 4.3.0) | 235 | htmlentities (~> 4.3.0) |
| 225 | inherited_resources | 236 | inherited_resources |
| 237 | + kaminari | ||
| 226 | lighthouse-api | 238 | lighthouse-api |
| 227 | mongoid (= 2.1.2) | 239 | mongoid (= 2.1.2) |
| 228 | mongoid_rails_migrations | 240 | mongoid_rails_migrations |
| @@ -232,6 +244,7 @@ DEPENDENCIES | @@ -232,6 +244,7 @@ DEPENDENCIES | ||
| 232 | pivotal-tracker | 244 | pivotal-tracker |
| 233 | rails (= 3.0.10) | 245 | rails (= 3.0.10) |
| 234 | ri_cal | 246 | ri_cal |
| 247 | + rpm_contrib! | ||
| 235 | rspec (~> 2.6) | 248 | rspec (~> 2.6) |
| 236 | rspec-rails (~> 2.6) | 249 | rspec-rails (~> 2.6) |
| 237 | ruby-debug | 250 | ruby-debug |
| @@ -240,4 +253,3 @@ DEPENDENCIES | @@ -240,4 +253,3 @@ DEPENDENCIES | ||
| 240 | thin | 253 | thin |
| 241 | useragent (~> 0.3.1) | 254 | useragent (~> 0.3.1) |
| 242 | webmock | 255 | webmock |
| 243 | - will_paginate (>= 3) |
app/controllers/apps_controller.rb
| @@ -15,7 +15,7 @@ class AppsController < InheritedResources::Base | @@ -15,7 +15,7 @@ class AppsController < InheritedResources::Base | ||
| 15 | 15 | ||
| 16 | @problems = resource.problems | 16 | @problems = resource.problems |
| 17 | @problems = @problems.unresolved unless @all_errs | 17 | @problems = @problems.unresolved unless @all_errs |
| 18 | - @problems = @problems.in_env(params[:environment]).ordered_by(@sort, @order).paginate(:page => params[:page], :per_page => current_user.per_page) | 18 | + @problems = @problems.in_env(params[:environment]).ordered_by(@sort, @order).page(params[:page]).per(current_user.per_page) |
| 19 | 19 | ||
| 20 | @selected_problems = params[:problems] || [] | 20 | @selected_problems = params[:problems] || [] |
| 21 | @deploys = @app.deploys.order_by(:created_at.desc).limit(5) | 21 | @deploys = @app.deploys.order_by(:created_at.desc).limit(5) |
app/controllers/deploys_controller.rb
| @@ -16,8 +16,8 @@ class DeploysController < ApplicationController | @@ -16,8 +16,8 @@ class DeploysController < ApplicationController | ||
| 16 | app = App.find(params[:app_id]) | 16 | app = App.find(params[:app_id]) |
| 17 | raise Mongoid::Errors::DocumentNotFound.new(App, app.id) unless current_user.admin? || current_user.watching?(app) | 17 | raise Mongoid::Errors::DocumentNotFound.new(App, app.id) unless current_user.admin? || current_user.watching?(app) |
| 18 | 18 | ||
| 19 | - @deploys = app.deploys.order_by(:created_at.desc). | ||
| 20 | - paginate(:page => params[:page], :per_page => 10) | 19 | + @deploys = Kaminari.paginate_array(app.deploys.order_by(:created_at.desc)). |
| 20 | + page(params[:page]).per(10) | ||
| 21 | @app = app | 21 | @app = app |
| 22 | end | 22 | end |
| 23 | 23 |
app/controllers/errs_controller.rb
| @@ -16,7 +16,7 @@ class ErrsController < ApplicationController | @@ -16,7 +16,7 @@ class ErrsController < ApplicationController | ||
| 16 | @selected_problems = params[:problems] || [] | 16 | @selected_problems = params[:problems] || [] |
| 17 | respond_to do |format| | 17 | respond_to do |format| |
| 18 | format.html do | 18 | format.html do |
| 19 | - @problems = @problems.paginate(:page => params[:page], :per_page => current_user.per_page) | 19 | + @problems = @problems.page(params[:page]).per(current_user.per_page) |
| 20 | end | 20 | end |
| 21 | format.atom | 21 | format.atom |
| 22 | end | 22 | end |
| @@ -24,14 +24,14 @@ class ErrsController < ApplicationController | @@ -24,14 +24,14 @@ class ErrsController < ApplicationController | ||
| 24 | 24 | ||
| 25 | def all | 25 | def all |
| 26 | app_scope = current_user.admin? ? App.all : current_user.apps | 26 | app_scope = current_user.admin? ? App.all : current_user.apps |
| 27 | - @problems = Problem.for_apps(app_scope).ordered.paginate(:page => params[:page], :per_page => current_user.per_page) | 27 | + @problems = Problem.for_apps(app_scope).ordered.page(params[:page]).per(current_user.per_page) |
| 28 | @selected_problems = params[:problems] || [] | 28 | @selected_problems = params[:problems] || [] |
| 29 | end | 29 | end |
| 30 | 30 | ||
| 31 | def show | 31 | def show |
| 32 | page = (params[:notice] || @problem.notices_count) | 32 | page = (params[:notice] || @problem.notices_count) |
| 33 | page = 1 if page.to_i.zero? | 33 | page = 1 if page.to_i.zero? |
| 34 | - @notices = @problem.notices.paginate(:page => page, :per_page => 1) | 34 | + @notices = @problem.notices.page(page.to_i).per(1) |
| 35 | @notice = @notices.first | 35 | @notice = @notices.first |
| 36 | @comment = Comment.new | 36 | @comment = Comment.new |
| 37 | if request.headers['X-PJAX'] | 37 | if request.headers['X-PJAX'] |
app/controllers/users_controller.rb
| @@ -6,7 +6,7 @@ class UsersController < ApplicationController | @@ -6,7 +6,7 @@ class UsersController < ApplicationController | ||
| 6 | before_filter :require_user_edit_priviledges, :only => [:edit, :update] | 6 | before_filter :require_user_edit_priviledges, :only => [:edit, :update] |
| 7 | 7 | ||
| 8 | def index | 8 | def index |
| 9 | - @users = User.all.paginate(:page => params[:page], :per_page => current_user.per_page) | 9 | + @users = User.all.page(params[:page]).per(current_user.per_page) |
| 10 | end | 10 | end |
| 11 | 11 | ||
| 12 | def show | 12 | def show |
app/helpers/application_helper.rb
| 1 | module ApplicationHelper | 1 | module ApplicationHelper |
| 2 | def message_graph(problem) | 2 | def message_graph(problem) |
| 3 | - create_percentage_table_for(problem) {|notice| notice.message} | 3 | + create_percentage_table_for(problem.messages) |
| 4 | end | 4 | end |
| 5 | 5 | ||
| 6 | def generate_problem_ical(notices) | 6 | def generate_problem_ical(notices) |
| @@ -35,35 +35,19 @@ module ApplicationHelper | @@ -35,35 +35,19 @@ module ApplicationHelper | ||
| 35 | end | 35 | end |
| 36 | 36 | ||
| 37 | def user_agent_graph(problem) | 37 | def user_agent_graph(problem) |
| 38 | - create_percentage_table_for(problem) {|notice| pretty_user_agent(notice.user_agent)} | ||
| 39 | - end | ||
| 40 | - | ||
| 41 | - def pretty_user_agent(user_agent) | ||
| 42 | - (user_agent.nil? || user_agent.none?) ? "N/A" : "#{user_agent.browser} #{user_agent.version}" | 38 | + create_percentage_table_for(problem.user_agents) |
| 43 | end | 39 | end |
| 44 | 40 | ||
| 45 | def tenant_graph(problem) | 41 | def tenant_graph(problem) |
| 46 | - create_percentage_table_for(problem) {|notice| get_host(notice.request['url'])} | ||
| 47 | - end | ||
| 48 | - | ||
| 49 | - def get_host(url) | ||
| 50 | - begin | ||
| 51 | - uri = url && URI.parse(url) | ||
| 52 | - uri.blank? ? "N/A" : uri.host | ||
| 53 | - rescue URI::InvalidURIError | ||
| 54 | - "N/A" | ||
| 55 | - end | 42 | + create_percentage_table_for(problem.hosts) |
| 56 | end | 43 | end |
| 57 | 44 | ||
| 58 | - | ||
| 59 | - def create_percentage_table_for(problem, &block) | ||
| 60 | - tallies = tally(problem.notices, &block) | ||
| 61 | - create_percentage_table_from_tallies(tallies, :total => problem.notices.count) | 45 | + def create_percentage_table_for(collection) |
| 46 | + create_percentage_table_from_tallies(tally(collection)) | ||
| 62 | end | 47 | end |
| 63 | 48 | ||
| 64 | - def tally(collection, &block) | ||
| 65 | - collection.inject({}) do |tallies, item| | ||
| 66 | - value = yield item | 49 | + def tally(collection) |
| 50 | + collection.inject({}) do |tallies, value| | ||
| 67 | tallies[value] = (tallies[value] || 0) + 1 | 51 | tallies[value] = (tallies[value] || 0) + 1 |
| 68 | tallies | 52 | tallies |
| 69 | end | 53 | end |
app/models/comment.rb
| @@ -2,12 +2,25 @@ class Comment | @@ -2,12 +2,25 @@ class Comment | ||
| 2 | include Mongoid::Document | 2 | include Mongoid::Document |
| 3 | include Mongoid::Timestamps | 3 | include Mongoid::Timestamps |
| 4 | 4 | ||
| 5 | + after_create :increase_counter_cache | ||
| 6 | + before_destroy :decrease_counter_cache | ||
| 7 | + | ||
| 5 | field :body, :type => String | 8 | field :body, :type => String |
| 6 | index :user_id | 9 | index :user_id |
| 7 | 10 | ||
| 8 | - belongs_to :err | 11 | + belongs_to :err, :class_name => "Problem" |
| 9 | belongs_to :user | 12 | belongs_to :user |
| 10 | 13 | ||
| 11 | validates_presence_of :body | 14 | validates_presence_of :body |
| 15 | + | ||
| 16 | + protected | ||
| 17 | + def increase_counter_cache | ||
| 18 | + err.inc(:comments_count, 1) | ||
| 19 | + end | ||
| 20 | + | ||
| 21 | + def decrease_counter_cache | ||
| 22 | + err.inc(:comments_count, -1) if err | ||
| 23 | + end | ||
| 24 | + | ||
| 12 | end | 25 | end |
| 13 | 26 |
app/models/notice.rb
| @@ -19,7 +19,7 @@ class Notice | @@ -19,7 +19,7 @@ class Notice | ||
| 19 | after_create :increase_counter_cache, :cache_attributes_on_problem, :unresolve_problem | 19 | after_create :increase_counter_cache, :cache_attributes_on_problem, :unresolve_problem |
| 20 | after_create :deliver_notification, :if => :should_notify? | 20 | after_create :deliver_notification, :if => :should_notify? |
| 21 | before_save :sanitize | 21 | before_save :sanitize |
| 22 | - before_destroy :decrease_counter_cache | 22 | + before_destroy :decrease_counter_cache, :remove_cached_attributes_from_problem |
| 23 | 23 | ||
| 24 | validates_presence_of :backtrace, :server_environment, :notifier | 24 | validates_presence_of :backtrace, :server_environment, :notifier |
| 25 | 25 | ||
| @@ -33,6 +33,10 @@ class Notice | @@ -33,6 +33,10 @@ class Notice | ||
| 33 | agent_string.blank? ? nil : UserAgent.parse(agent_string) | 33 | agent_string.blank? ? nil : UserAgent.parse(agent_string) |
| 34 | end | 34 | end |
| 35 | 35 | ||
| 36 | + def user_agent_string | ||
| 37 | + (user_agent.nil? || user_agent.none?) ? "N/A" : "#{user_agent.browser} #{user_agent.version}" | ||
| 38 | + end | ||
| 39 | + | ||
| 36 | def environment_name | 40 | def environment_name |
| 37 | server_environment['server-environment'] || server_environment['environment-name'] | 41 | server_environment['server-environment'] || server_environment['environment-name'] |
| 38 | end | 42 | end |
| @@ -59,6 +63,17 @@ class Notice | @@ -59,6 +63,17 @@ class Notice | ||
| 59 | read_attribute(:request) || {} | 63 | read_attribute(:request) || {} |
| 60 | end | 64 | end |
| 61 | 65 | ||
| 66 | + def url | ||
| 67 | + request['url'] | ||
| 68 | + end | ||
| 69 | + | ||
| 70 | + def host | ||
| 71 | + uri = url && URI.parse(url) | ||
| 72 | + uri.blank? ? "N/A" : uri.host | ||
| 73 | + rescue URI::InvalidURIError | ||
| 74 | + "N/A" | ||
| 75 | + end | ||
| 76 | + | ||
| 62 | def env_vars | 77 | def env_vars |
| 63 | request['cgi-data'] || {} | 78 | request['cgi-data'] || {} |
| 64 | end | 79 | end |
| @@ -94,11 +109,14 @@ class Notice | @@ -94,11 +109,14 @@ class Notice | ||
| 94 | problem.inc(:notices_count, -1) if err | 109 | problem.inc(:notices_count, -1) if err |
| 95 | end | 110 | end |
| 96 | 111 | ||
| 112 | + def remove_cached_attributes_from_problem | ||
| 113 | + problem.remove_cached_notice_attribures(self) if err | ||
| 114 | + end | ||
| 115 | + | ||
| 97 | def unresolve_problem | 116 | def unresolve_problem |
| 98 | problem.update_attribute(:resolved, false) if problem.resolved? | 117 | problem.update_attribute(:resolved, false) if problem.resolved? |
| 99 | end | 118 | end |
| 100 | 119 | ||
| 101 | - | ||
| 102 | def cache_attributes_on_problem | 120 | def cache_attributes_on_problem |
| 103 | problem.cache_notice_attributes(self) | 121 | problem.cache_notice_attributes(self) |
| 104 | end | 122 | end |
app/models/problem.rb
| @@ -18,6 +18,10 @@ class Problem | @@ -18,6 +18,10 @@ class Problem | ||
| 18 | field :environment | 18 | field :environment |
| 19 | field :klass | 19 | field :klass |
| 20 | field :where | 20 | field :where |
| 21 | + field :user_agents, :type => Array, :default => [] | ||
| 22 | + field :messages, :type => Array, :default => [] | ||
| 23 | + field :hosts, :type => Array, :default => [] | ||
| 24 | + field :comments_count, :type => Integer, :default => 0 | ||
| 21 | 25 | ||
| 22 | index :app_id | 26 | index :app_id |
| 23 | index :app_name | 27 | index :app_name |
| @@ -123,8 +127,20 @@ class Problem | @@ -123,8 +127,20 @@ class Problem | ||
| 123 | :message => notice.message, | 127 | :message => notice.message, |
| 124 | :environment => notice.environment_name, | 128 | :environment => notice.environment_name, |
| 125 | :klass => notice.klass, | 129 | :klass => notice.klass, |
| 126 | - :where => notice.where) if notice | 130 | + :where => notice.where, |
| 131 | + :messages => messages.push(notice.message), | ||
| 132 | + :hosts => hosts.push(notice.host), | ||
| 133 | + :user_agents => user_agents.push(notice.user_agent_string) | ||
| 134 | + ) if notice | ||
| 127 | update_attributes!(attrs) | 135 | update_attributes!(attrs) |
| 128 | end | 136 | end |
| 137 | + | ||
| 138 | + def remove_cached_notice_attribures(notice) | ||
| 139 | + messages.delete_at(messages.index(notice.message)) | ||
| 140 | + hosts.delete_at(hosts.index(notice.host)) | ||
| 141 | + user_agents.delete_at(user_agents.index(notice.user_agent_string)) | ||
| 142 | + save! | ||
| 143 | + end | ||
| 144 | + | ||
| 129 | end | 145 | end |
| 130 | 146 |
app/views/deploys/index.html.haml
| @@ -3,5 +3,5 @@ | @@ -3,5 +3,5 @@ | ||
| 3 | - if current_user.authentication_token | 3 | - if current_user.authentication_token |
| 4 | %span= link_to 'iCal', app_deploys_path(@app, :format => "ics", :auth_token => current_user.authentication_token), :class => "calendar_link" | 4 | %span= link_to 'iCal', app_deploys_path(@app, :format => "ics", :auth_token => current_user.authentication_token), :class => "calendar_link" |
| 5 | = render 'table', :deploys => @deploys | 5 | = render 'table', :deploys => @deploys |
| 6 | -= will_paginate @deploys, :previous_label => '« Previous', :next_label => 'Next »' | 6 | += paginate @deploys |
| 7 | 7 |
app/views/errs/_table.html.haml
| @@ -26,7 +26,7 @@ | @@ -26,7 +26,7 @@ | ||
| 26 | %td.message | 26 | %td.message |
| 27 | = link_to trucated_err_message(problem), app_err_path(problem.app, problem) | 27 | = link_to trucated_err_message(problem), app_err_path(problem.app, problem) |
| 28 | %em= problem.where | 28 | %em= problem.where |
| 29 | - - if problem.comments.any? | 29 | + - if problem.comments_count > 0 |
| 30 | - comment = problem.comments.last | 30 | - comment = problem.comments.last |
| 31 | %br | 31 | %br |
| 32 | .inline_comment | 32 | .inline_comment |
| @@ -34,7 +34,7 @@ | @@ -34,7 +34,7 @@ | ||
| 34 | %em= truncate(comment.body, :length => 100, :separator => ' ') | 34 | %em= truncate(comment.body, :length => 100, :separator => ' ') |
| 35 | %td.latest #{time_ago_in_words(last_notice_at problem)} ago | 35 | %td.latest #{time_ago_in_words(last_notice_at problem)} ago |
| 36 | %td.deploy= problem.last_deploy_at ? problem.last_deploy_at.to_s(:micro) : 'n/a' | 36 | %td.deploy= problem.last_deploy_at ? problem.last_deploy_at.to_s(:micro) : 'n/a' |
| 37 | - %td.count= link_to problem.notices.count, app_err_path(problem.app, problem) | 37 | + %td.count= link_to problem.notices_count, app_err_path(problem.app, problem) |
| 38 | - if any_issue_links | 38 | - if any_issue_links |
| 39 | %td.issue_link | 39 | %td.issue_link |
| 40 | - if problem.issue_link.present? | 40 | - if problem.issue_link.present? |
| @@ -44,7 +44,7 @@ | @@ -44,7 +44,7 @@ | ||
| 44 | %tr | 44 | %tr |
| 45 | %td{:colspan => (@app ? 5 : 6)} | 45 | %td{:colspan => (@app ? 5 : 6)} |
| 46 | %em No errs here | 46 | %em No errs here |
| 47 | - = will_paginate @problems, :previous_label => '« Previous', :next_label => 'Next »' | 47 | + = paginate errs |
| 48 | .tab-bar | 48 | .tab-bar |
| 49 | %ul | 49 | %ul |
| 50 | %li= submit_tag 'Merge', :id => 'merge_errs', :class => 'button', 'data-action' => merge_several_errs_path | 50 | %li= submit_tag 'Merge', :id => 'merge_errs', :class => 'button', 'data-action' => merge_several_errs_path |
app/views/errs/show.html.haml
| @@ -43,9 +43,7 @@ | @@ -43,9 +43,7 @@ | ||
| 43 | 43 | ||
| 44 | %h4= @notice.try(:message) | 44 | %h4= @notice.try(:message) |
| 45 | 45 | ||
| 46 | -= will_paginate @notices, :param_name => :notice, :page_links => false, :class => 'notice-pagination' | ||
| 47 | -viewing occurrence #{@notices.current_page} of #{@notices.total_pages} | ||
| 48 | -.notice-pagination-loader= image_tag 'loader.gif' | 46 | += paginate @notices, :param_name => :notice, :theme => :notices |
| 49 | 47 | ||
| 50 | .tab-bar | 48 | .tab-bar |
| 51 | %ul | 49 | %ul |
| @@ -58,7 +56,7 @@ viewing occurrence #{@notices.current_page} of #{@notices.total_pages} | @@ -58,7 +56,7 @@ viewing occurrence #{@notices.current_page} of #{@notices.total_pages} | ||
| 58 | - if @notice | 56 | - if @notice |
| 59 | #summary | 57 | #summary |
| 60 | %h3 Summary | 58 | %h3 Summary |
| 61 | - = render 'notices/summary', :notice => @notice | 59 | + = render 'notices/summary', :notice => @notice, :problem => @problem |
| 62 | 60 | ||
| 63 | #backtrace | 61 | #backtrace |
| 64 | %h3 Backtrace | 62 | %h3 Backtrace |
app/views/issue_trackers/pivotal_body.txt.erb
| @@ -3,7 +3,7 @@ See this exception on Errbit: <%= app_err_url problem.app, problem %> | @@ -3,7 +3,7 @@ See this exception on Errbit: <%= app_err_url problem.app, problem %> | ||
| 3 | <% if notice.request['url'].present? %>URL: <%= notice.request['url'] %><% end %> | 3 | <% if notice.request['url'].present? %>URL: <%= notice.request['url'] %><% end %> |
| 4 | Where: <%= notice.where %> | 4 | Where: <%= notice.where %> |
| 5 | Occurred: <%= notice.created_at.to_s :micro %> | 5 | Occurred: <%= notice.created_at.to_s :micro %> |
| 6 | - Similar: <%= (notice.problem.notices.count - 1).to_s %> | 6 | + Similar: <%= (notice.problem.notices_count - 1).to_s %> |
| 7 | 7 | ||
| 8 | Params: | 8 | Params: |
| 9 | <%= pretty_hash notice.params %> | 9 | <%= pretty_hash notice.params %> |
| @@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
| 1 | +-# Link to the "First" page | ||
| 2 | +-# available local variables | ||
| 3 | +-# url: url to the first page | ||
| 4 | +-# current_page: a page object for the currently displayed page | ||
| 5 | +-# num_pages: total number of pages | ||
| 6 | +-# per_page: number of items to fetch per page | ||
| 7 | +-# remote: data-remote | ||
| 8 | +%span.first | ||
| 9 | + = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote |
| @@ -0,0 +1,8 @@ | @@ -0,0 +1,8 @@ | ||
| 1 | +-# Non-link tag that stands for skipped pages... | ||
| 2 | +-# available local variables | ||
| 3 | +-# current_page: a page object for the currently displayed page | ||
| 4 | +-# num_pages: total number of pages | ||
| 5 | +-# per_page: number of items to fetch per page | ||
| 6 | +-# remote: data-remote | ||
| 7 | +%span.page.gap | ||
| 8 | + = raw(t 'views.pagination.truncate') |
| @@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
| 1 | +-# Link to the "Last" page | ||
| 2 | +-# available local variables | ||
| 3 | +-# url: url to the last page | ||
| 4 | +-# current_page: a page object for the currently displayed page | ||
| 5 | +-# num_pages: total number of pages | ||
| 6 | +-# per_page: number of items to fetch per page | ||
| 7 | +-# remote: data-remote | ||
| 8 | +%span.last | ||
| 9 | + = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {:remote => remote} |
| @@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
| 1 | +-# Link to the "Next" page | ||
| 2 | +-# available local variables | ||
| 3 | +-# url: url to the next page | ||
| 4 | +-# current_page: a page object for the currently displayed page | ||
| 5 | +-# num_pages: total number of pages | ||
| 6 | +-# per_page: number of items to fetch per page | ||
| 7 | +-# remote: data-remote | ||
| 8 | +%span.next | ||
| 9 | + = link_to_unless current_page.last?, raw('Next »'), url, :rel => 'next' |
| @@ -0,0 +1,10 @@ | @@ -0,0 +1,10 @@ | ||
| 1 | +-# Link showing page number | ||
| 2 | +-# available local variables | ||
| 3 | +-# page: a page object for "this" page | ||
| 4 | +-# url: url to this page | ||
| 5 | +-# current_page: a page object for the currently displayed page | ||
| 6 | +-# num_pages: total number of pages | ||
| 7 | +-# per_page: number of items to fetch per page | ||
| 8 | +-# remote: data-remote | ||
| 9 | +%span{:class => "page#{' current' if page.current?}"} | ||
| 10 | + = link_to_unless page.current?, page, url, {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil} |
| @@ -0,0 +1,16 @@ | @@ -0,0 +1,16 @@ | ||
| 1 | +-# The container tag | ||
| 2 | +-# available local variables | ||
| 3 | +-# current_page: a page object for the currently displayed page | ||
| 4 | +-# num_pages: total number of pages | ||
| 5 | +-# per_page: number of items to fetch per page | ||
| 6 | +-# remote: data-remote | ||
| 7 | +-# paginator: the paginator that renders the pagination tags inside | ||
| 8 | += paginator.render do | ||
| 9 | + %nav.pagination | ||
| 10 | + = prev_page_tag | ||
| 11 | + - each_page do |page| | ||
| 12 | + - if page.left_outer? || page.right_outer? || page.inside_window? | ||
| 13 | + = page_tag page | ||
| 14 | + - elsif !page.was_truncated? | ||
| 15 | + = gap_tag | ||
| 16 | + = next_page_tag |
| @@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
| 1 | +-# Link to the "Previous" page | ||
| 2 | +-# available local variables | ||
| 3 | +-# url: url to the previous page | ||
| 4 | +-# current_page: a page object for the currently displayed page | ||
| 5 | +-# num_pages: total number of pages | ||
| 6 | +-# per_page: number of items to fetch per page | ||
| 7 | +-# remote: data-remote | ||
| 8 | +%span.prev | ||
| 9 | + = link_to_unless current_page.first?, raw('« Previous'), url, :rel => 'prev' |
| @@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
| 1 | +-# Link to the "First" page | ||
| 2 | +-# available local variables | ||
| 3 | +-# url: url to the first page | ||
| 4 | +-# current_page: a page object for the currently displayed page | ||
| 5 | +-# num_pages: total number of pages | ||
| 6 | +-# per_page: number of items to fetch per page | ||
| 7 | +-# remote: data-remote | ||
| 8 | +%span.first | ||
| 9 | + = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote |
| @@ -0,0 +1,8 @@ | @@ -0,0 +1,8 @@ | ||
| 1 | +-# Non-link tag that stands for skipped pages... | ||
| 2 | +-# available local variables | ||
| 3 | +-# current_page: a page object for the currently displayed page | ||
| 4 | +-# num_pages: total number of pages | ||
| 5 | +-# per_page: number of items to fetch per page | ||
| 6 | +-# remote: data-remote | ||
| 7 | +%span.page.gap | ||
| 8 | + = raw(t 'views.pagination.truncate') |
| @@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
| 1 | +-# Link to the "Last" page | ||
| 2 | +-# available local variables | ||
| 3 | +-# url: url to the last page | ||
| 4 | +-# current_page: a page object for the currently displayed page | ||
| 5 | +-# num_pages: total number of pages | ||
| 6 | +-# per_page: number of items to fetch per page | ||
| 7 | +-# remote: data-remote | ||
| 8 | +%span.last | ||
| 9 | + = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {:remote => remote} |
| @@ -0,0 +1,10 @@ | @@ -0,0 +1,10 @@ | ||
| 1 | +-# Link showing page number | ||
| 2 | +-# available local variables | ||
| 3 | +-# page: a page object for "this" page | ||
| 4 | +-# url: url to this page | ||
| 5 | +-# current_page: a page object for the currently displayed page | ||
| 6 | +-# num_pages: total number of pages | ||
| 7 | +-# per_page: number of items to fetch per page | ||
| 8 | +-# remote: data-remote | ||
| 9 | +%span{:class => "page#{' current' if page.current?}"} | ||
| 10 | + = link_to_unless page.current?, page, url, {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil} |
| @@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
| 1 | +-# The container tag | ||
| 2 | +-# available local variables | ||
| 3 | +-# current_page: a page object for the currently displayed page | ||
| 4 | +-# num_pages: total number of pages | ||
| 5 | +-# per_page: number of items to fetch per page | ||
| 6 | +-# remote: data-remote | ||
| 7 | +-# paginator: the paginator that renders the pagination tags inside | ||
| 8 | += paginator.render do | ||
| 9 | + .notice-pagination< | ||
| 10 | + = prev_page_tag | ||
| 11 | + = next_page_tag | ||
| 12 | +.notice-pagination-loader= image_tag 'loader.gif' | ||
| 13 | +viewing occurrence #{current_page} of #{num_pages} |
app/views/notices/_summary.html.haml
| @@ -2,7 +2,7 @@ | @@ -2,7 +2,7 @@ | ||
| 2 | %table.summary | 2 | %table.summary |
| 3 | %tr | 3 | %tr |
| 4 | %th Message | 4 | %th Message |
| 5 | - %td.main.nowrap= message_graph(notice.problem) | 5 | + %td.main.nowrap= message_graph(problem) |
| 6 | - if notice.request['url'].present? | 6 | - if notice.request['url'].present? |
| 7 | %tr | 7 | %tr |
| 8 | %th URL | 8 | %th URL |
| @@ -15,13 +15,13 @@ | @@ -15,13 +15,13 @@ | ||
| 15 | %td= notice.created_at.to_s(:micro) | 15 | %td= notice.created_at.to_s(:micro) |
| 16 | %tr | 16 | %tr |
| 17 | %th Similar | 17 | %th Similar |
| 18 | - %td= notice.problem.notices.count - 1 | 18 | + %td= problem.notices_count - 1 |
| 19 | %tr | 19 | %tr |
| 20 | %th Browser | 20 | %th Browser |
| 21 | - %td= user_agent_graph(notice.problem) | 21 | + %td= user_agent_graph(problem) |
| 22 | %tr | 22 | %tr |
| 23 | %th Tenant | 23 | %th Tenant |
| 24 | - %td= tenant_graph(notice.problem) | 24 | + %td= tenant_graph(problem) |
| 25 | %tr | 25 | %tr |
| 26 | %th App Server | 26 | %th App Server |
| 27 | %td= notice.server_environment && notice.server_environment["hostname"] | 27 | %td= notice.server_environment && notice.server_environment["hostname"] |
app/views/users/index.html.haml
| @@ -18,5 +18,5 @@ | @@ -18,5 +18,5 @@ | ||
| 18 | %td= user.username | 18 | %td= user.username |
| 19 | %td= user.email | 19 | %td= user.email |
| 20 | %td= user.admin? ? 'Y' : 'N' | 20 | %td= user.admin? ? 'Y' : 'N' |
| 21 | -= will_paginate @users, :previous_label => '« Previous', :next_label => 'Next »' | 21 | += paginate @users |
| 22 | 22 |
config/application.rb
| @@ -7,7 +7,6 @@ require "action_controller/railtie" | @@ -7,7 +7,6 @@ require "action_controller/railtie" | ||
| 7 | require "action_mailer/railtie" | 7 | require "action_mailer/railtie" |
| 8 | # require "active_resource/railtie" | 8 | # require "active_resource/railtie" |
| 9 | require 'mongoid/railtie' | 9 | require 'mongoid/railtie' |
| 10 | -require 'will_paginate/array' # make paginate available on Array | ||
| 11 | 10 | ||
| 12 | 11 | ||
| 13 | # If you have a Gemfile, require the gems listed there, including any gems | 12 | # If you have a Gemfile, require the gems listed there, including any gems |
| @@ -0,0 +1,226 @@ | @@ -0,0 +1,226 @@ | ||
| 1 | +# | ||
| 2 | +# This file configures the New Relic Agent. New Relic monitors | ||
| 3 | +# Ruby, Java, .NET, PHP, and Python applications with deep visibility and low overhead. | ||
| 4 | +# For more information, visit www.newrelic.com. | ||
| 5 | +# | ||
| 6 | +# Generated October 18, 2011 | ||
| 7 | +# | ||
| 8 | +# This configuration file is custom generated for errbit | ||
| 9 | + | ||
| 10 | +# Here are the settings that are common to all environments: | ||
| 11 | +common: &default_settings | ||
| 12 | + # ============================== LICENSE KEY =============================== | ||
| 13 | + | ||
| 14 | + # You must specify the license key associated with your New Relic | ||
| 15 | + # account. This key binds your Agent's data to your account in the | ||
| 16 | + # New Relic service. | ||
| 17 | + license_key: <%= ENV["NEW_RELIC_LICENSE_KEY"] %> | ||
| 18 | + | ||
| 19 | + # Agent Enabled (Ruby/Rails Only) | ||
| 20 | + # Use this setting to force the agent to run or not run. | ||
| 21 | + # Default is 'auto' which means the agent will install and run only | ||
| 22 | + # if a valid dispatcher such as Mongrel is running. This prevents | ||
| 23 | + # it from running with Rake or the console. Set to false to | ||
| 24 | + # completely turn the agent off regardless of the other settings. | ||
| 25 | + # Valid values are true, false and auto. | ||
| 26 | + # agent_enabled: auto | ||
| 27 | + | ||
| 28 | + # Application Name | ||
| 29 | + # Set this to be the name of your application as you'd like it show | ||
| 30 | + # up in New Relic. New Relic will then auto-map instances of your application | ||
| 31 | + # into a New Relic "application" on your home dashboard page. If you want | ||
| 32 | + # to map this instance into multiple apps, like "AJAX Requests" and | ||
| 33 | + # "All UI" then specify a semicolon-separated list of up to three | ||
| 34 | + # distinct names. If you comment this out, it defaults to the | ||
| 35 | + # capitalized RAILS_ENV (i.e., Production, Staging, etc) | ||
| 36 | + app_name: <%= ENV["NEW_RELIC_APP_NAME"] %> | ||
| 37 | + | ||
| 38 | + # When "true", the agent collects performance data about your | ||
| 39 | + # application and reports this data to the New Relic service at | ||
| 40 | + # newrelic.com. This global switch is normally overridden for each | ||
| 41 | + # environment below. (formerly called 'enabled') | ||
| 42 | + monitor_mode: true | ||
| 43 | + | ||
| 44 | + # Developer mode should be off in every environment but | ||
| 45 | + # development as it has very high overhead in memory. | ||
| 46 | + developer_mode: false | ||
| 47 | + | ||
| 48 | + # The newrelic agent generates its own log file to keep its logging | ||
| 49 | + # information separate from that of your application. Specify its | ||
| 50 | + # log level here. | ||
| 51 | + log_level: info | ||
| 52 | + | ||
| 53 | + # The newrelic agent communicates with the New Relic service via http by | ||
| 54 | + # default. If you want to communicate via https to increase | ||
| 55 | + # security, then turn on SSL by setting this value to true. Note, | ||
| 56 | + # this will result in increased CPU overhead to perform the | ||
| 57 | + # encryption involved in SSL communication, but this work is done | ||
| 58 | + # asynchronously to the threads that process your application code, | ||
| 59 | + # so it should not impact response times. | ||
| 60 | + ssl: false | ||
| 61 | + | ||
| 62 | + # EXPERIMENTAL: enable verification of the SSL certificate sent by | ||
| 63 | + # the server. This setting has no effect unless SSL is enabled | ||
| 64 | + # above. This may block your application. Only enable it if the data | ||
| 65 | + # you send us needs end-to-end verified certificates. | ||
| 66 | + # | ||
| 67 | + # This means we cannot cache the DNS lookup, so each request to the | ||
| 68 | + # New Relic service will perform a lookup. It also means that we cannot | ||
| 69 | + # use a non-blocking lookup, so in a worst case, if you have DNS | ||
| 70 | + # problems, your app may block indefinitely. | ||
| 71 | + # verify_certificate: true | ||
| 72 | + | ||
| 73 | + # Set your application's Apdex threshold value with the 'apdex_t' | ||
| 74 | + # setting, in seconds. The apdex_t value determines the buckets used | ||
| 75 | + # to compute your overall Apdex score. | ||
| 76 | + # Requests that take less than apdex_t seconds to process will be | ||
| 77 | + # classified as Satisfying transactions; more than apdex_t seconds | ||
| 78 | + # as Tolerating transactions; and more than four times the apdex_t | ||
| 79 | + # value as Frustrating transactions. | ||
| 80 | + # For more about the Apdex standard, see | ||
| 81 | + # http://support.newrelic.com/faqs/general/apdex | ||
| 82 | + apdex_t: 0.5 | ||
| 83 | + | ||
| 84 | + # Proxy settings for connecting to the New Relic server. | ||
| 85 | + # | ||
| 86 | + # If a proxy is used, the host setting is required. Other settings | ||
| 87 | + # are optional. Default port is 8080. | ||
| 88 | + # | ||
| 89 | + # proxy_host: hostname | ||
| 90 | + # proxy_port: 8080 | ||
| 91 | + # proxy_user: | ||
| 92 | + # proxy_pass: | ||
| 93 | + | ||
| 94 | + # Tells transaction tracer and error collector (when enabled) | ||
| 95 | + # whether or not to capture HTTP params. When true, frameworks can | ||
| 96 | + # exclude HTTP parameters from being captured. | ||
| 97 | + # Rails: the RoR filter_parameter_logging excludes parameters | ||
| 98 | + # Java: create a config setting called "ignored_params" and set it to | ||
| 99 | + # a comma separated list of HTTP parameter names. | ||
| 100 | + # ex: ignored_params: credit_card, ssn, password | ||
| 101 | + capture_params: false | ||
| 102 | + | ||
| 103 | + # Transaction tracer captures deep information about slow | ||
| 104 | + # transactions and sends this to the New Relic service once a | ||
| 105 | + # minute. Included in the transaction is the exact call sequence of | ||
| 106 | + # the transactions including any SQL statements issued. | ||
| 107 | + transaction_tracer: | ||
| 108 | + | ||
| 109 | + # Transaction tracer is enabled by default. Set this to false to | ||
| 110 | + # turn it off. This feature is only available at the Professional | ||
| 111 | + # product level. | ||
| 112 | + enabled: true | ||
| 113 | + | ||
| 114 | + # Threshold in seconds for when to collect a transaction | ||
| 115 | + # trace. When the response time of a controller action exceeds | ||
| 116 | + # this threshold, a transaction trace will be recorded and sent to | ||
| 117 | + # New Relic. Valid values are any float value, or (default) "apdex_f", | ||
| 118 | + # which will use the threshold for an dissatisfying Apdex | ||
| 119 | + # controller action - four times the Apdex T value. | ||
| 120 | + transaction_threshold: apdex_f | ||
| 121 | + | ||
| 122 | + # When transaction tracer is on, SQL statements can optionally be | ||
| 123 | + # recorded. The recorder has three modes, "off" which sends no | ||
| 124 | + # SQL, "raw" which sends the SQL statement in its original form, | ||
| 125 | + # and "obfuscated", which strips out numeric and string literals. | ||
| 126 | + record_sql: obfuscated | ||
| 127 | + | ||
| 128 | + # Threshold in seconds for when to collect stack trace for a SQL | ||
| 129 | + # call. In other words, when SQL statements exceed this threshold, | ||
| 130 | + # then capture and send to New Relic the current stack trace. This is | ||
| 131 | + # helpful for pinpointing where long SQL calls originate from. | ||
| 132 | + stack_trace_threshold: 0.500 | ||
| 133 | + | ||
| 134 | + # Determines whether the agent will capture query plans for slow | ||
| 135 | + # SQL queries. Only supported in mysql and postgres. Should be | ||
| 136 | + # set to false when using other adapters. | ||
| 137 | + # explain_enabled: true | ||
| 138 | + | ||
| 139 | + # Threshold for query execution time below which query plans will not | ||
| 140 | + # not be captured. Relevant only when `explain_enabled` is true. | ||
| 141 | + # explain_threshold: 0.5 | ||
| 142 | + | ||
| 143 | + # Error collector captures information about uncaught exceptions and | ||
| 144 | + # sends them to New Relic for viewing | ||
| 145 | + error_collector: | ||
| 146 | + | ||
| 147 | + # Error collector is enabled by default. Set this to false to turn | ||
| 148 | + # it off. This feature is only available at the Professional | ||
| 149 | + # product level. | ||
| 150 | + enabled: true | ||
| 151 | + | ||
| 152 | + # Rails Only - tells error collector whether or not to capture a | ||
| 153 | + # source snippet around the place of the error when errors are View | ||
| 154 | + # related. | ||
| 155 | + capture_source: true | ||
| 156 | + | ||
| 157 | + # To stop specific errors from reporting to New Relic, set this property | ||
| 158 | + # to comma-separated values. Default is to ignore routing errors, | ||
| 159 | + # which are how 404's get triggered. | ||
| 160 | + ignore_errors: ActionController::RoutingError | ||
| 161 | + | ||
| 162 | + # (Advanced) Uncomment this to ensure the CPU and memory samplers | ||
| 163 | + # won't run. Useful when you are using the agent to monitor an | ||
| 164 | + # external resource | ||
| 165 | + # disable_samplers: true | ||
| 166 | + | ||
| 167 | + # If you aren't interested in visibility in these areas, you can | ||
| 168 | + # disable the instrumentation to reduce overhead. | ||
| 169 | + # | ||
| 170 | + # disable_view_instrumentation: true | ||
| 171 | + # disable_activerecord_instrumentation: true | ||
| 172 | + # disable_memcache_instrumentation: true | ||
| 173 | + # disable_dj: true | ||
| 174 | + | ||
| 175 | + # Certain types of instrumentation such as GC stats will not work if | ||
| 176 | + # you are running multi-threaded. Please let us know. | ||
| 177 | + # multi_threaded = false | ||
| 178 | + | ||
| 179 | +# Application Environments | ||
| 180 | +# ------------------------------------------ | ||
| 181 | +# Environment-specific settings are in this section. | ||
| 182 | +# For Rails applications, RAILS_ENV is used to determine the environment. | ||
| 183 | +# For Java applications, pass -Dnewrelic.environment <environment> to set | ||
| 184 | +# the environment. | ||
| 185 | + | ||
| 186 | +# NOTE if your application has other named environments, you should | ||
| 187 | +# provide newrelic configuration settings for these environments here. | ||
| 188 | + | ||
| 189 | +development: | ||
| 190 | + <<: *default_settings | ||
| 191 | + # Turn off communication to New Relic service in development mode (also | ||
| 192 | + # 'enabled'). | ||
| 193 | + # NOTE: for initial evaluation purposes, you may want to temporarily | ||
| 194 | + # turn agent communication on in development mode. | ||
| 195 | + monitor_mode: false | ||
| 196 | + | ||
| 197 | + # Rails Only - when running in Developer Mode, the New Relic Agent will | ||
| 198 | + # present performance information on the last 100 transactions you have | ||
| 199 | + # executed since starting the app server. | ||
| 200 | + # NOTE: There is substantial overhead when running in developer mode. | ||
| 201 | + # Do not use for production or load testing. | ||
| 202 | + developer_mode: true | ||
| 203 | + | ||
| 204 | + # Enable textmate links | ||
| 205 | + # textmate: true | ||
| 206 | + | ||
| 207 | +test: | ||
| 208 | + <<: *default_settings | ||
| 209 | + # It almost never makes sense to turn on the agent when running | ||
| 210 | + # unit, functional or integration tests or the like. | ||
| 211 | + monitor_mode: false | ||
| 212 | + | ||
| 213 | +# Turn on the agent in production for 24x7 monitoring. New Relic | ||
| 214 | +# testing shows an average performance impact of < 5 ms per | ||
| 215 | +# transaction, so you can leave this on all the time without | ||
| 216 | +# incurring any user-visible performance degradation. | ||
| 217 | +production: | ||
| 218 | + <<: *default_settings | ||
| 219 | + monitor_mode: true | ||
| 220 | + | ||
| 221 | +# Many applications have a staging environment which behaves | ||
| 222 | +# identically to production. Support for that environment is provided | ||
| 223 | +# here. By default, the staging environment has the agent turned on. | ||
| 224 | +staging: | ||
| 225 | + <<: *default_settings | ||
| 226 | + monitor_mode: true |
| @@ -0,0 +1,18 @@ | @@ -0,0 +1,18 @@ | ||
| 1 | +class CacheProblemStatistics < Mongoid::Migration | ||
| 2 | + def self.up | ||
| 3 | + Problem.all.each do |problem| | ||
| 4 | + problem.notices.each do |notice| | ||
| 5 | + problem.messages << notice.message | ||
| 6 | + problem.hosts << notice.host | ||
| 7 | + problem.user_agents << notice.user_agent_string | ||
| 8 | + end | ||
| 9 | + problem.save! | ||
| 10 | + end | ||
| 11 | + end | ||
| 12 | + | ||
| 13 | + def self.down | ||
| 14 | + Problem.all.each do |problem| | ||
| 15 | + problem.update_attributes(:messages => [], :hosts => [], :user_agents => []) | ||
| 16 | + end | ||
| 17 | + end | ||
| 18 | +end | ||
| 0 | \ No newline at end of file | 19 | \ No newline at end of file |
| @@ -0,0 +1,10 @@ | @@ -0,0 +1,10 @@ | ||
| 1 | +class AddProblemCommentsCount < Mongoid::Migration | ||
| 2 | + def self.up | ||
| 3 | + Problem.all.each do |problem| | ||
| 4 | + problem.update_attributes(:comments_count => problem.comments.count) | ||
| 5 | + end | ||
| 6 | + end | ||
| 7 | + | ||
| 8 | + def self.down | ||
| 9 | + end | ||
| 10 | +end | ||
| 0 | \ No newline at end of file | 11 | \ No newline at end of file |
spec/controllers/apps_controller_spec.rb
| @@ -65,13 +65,13 @@ describe AppsController do | @@ -65,13 +65,13 @@ describe AppsController do | ||
| 65 | 65 | ||
| 66 | it "should have default per_page value for user" do | 66 | it "should have default per_page value for user" do |
| 67 | get :show, :id => @app.id | 67 | get :show, :id => @app.id |
| 68 | - assigns(:problems).size.should == User::PER_PAGE | 68 | + assigns(:problems).to_a.size.should == User::PER_PAGE |
| 69 | end | 69 | end |
| 70 | 70 | ||
| 71 | it "should be able to override default per_page value" do | 71 | it "should be able to override default per_page value" do |
| 72 | @user.update_attribute :per_page, 10 | 72 | @user.update_attribute :per_page, 10 |
| 73 | get :show, :id => @app.id | 73 | get :show, :id => @app.id |
| 74 | - assigns(:problems).size.should == 10 | 74 | + assigns(:problems).to_a.size.should == 10 |
| 75 | end | 75 | end |
| 76 | end | 76 | end |
| 77 | 77 |
spec/controllers/errs_controller_spec.rb
| @@ -39,13 +39,13 @@ describe ErrsController do | @@ -39,13 +39,13 @@ describe ErrsController do | ||
| 39 | 39 | ||
| 40 | it "should have default per_page value for user" do | 40 | it "should have default per_page value for user" do |
| 41 | get :index | 41 | get :index |
| 42 | - assigns(:problems).size.should == User::PER_PAGE | 42 | + assigns(:problems).to_a.size.should == User::PER_PAGE |
| 43 | end | 43 | end |
| 44 | 44 | ||
| 45 | it "should be able to override default per_page value" do | 45 | it "should be able to override default per_page value" do |
| 46 | @user.update_attribute :per_page, 10 | 46 | @user.update_attribute :per_page, 10 |
| 47 | get :index | 47 | get :index |
| 48 | - assigns(:problems).size.should == 10 | 48 | + assigns(:problems).to_a.size.should == 10 |
| 49 | end | 49 | end |
| 50 | end | 50 | end |
| 51 | 51 | ||
| @@ -111,11 +111,11 @@ describe ErrsController do | @@ -111,11 +111,11 @@ describe ErrsController do | ||
| 111 | context 'when logged in as an admin' do | 111 | context 'when logged in as an admin' do |
| 112 | it "gets a paginated list of all errs" do | 112 | it "gets a paginated list of all errs" do |
| 113 | sign_in Factory(:admin) | 113 | sign_in Factory(:admin) |
| 114 | - errs = WillPaginate::Collection.new(1,30) | 114 | + errs = Kaminari.paginate_array((1..30).to_a) |
| 115 | 3.times { errs << Factory(:err).problem } | 115 | 3.times { errs << Factory(:err).problem } |
| 116 | 3.times { errs << Factory(:err, :problem => Factory(:problem, :resolved => true)).problem } | 116 | 3.times { errs << Factory(:err, :problem => Factory(:problem, :resolved => true)).problem } |
| 117 | Problem.should_receive(:ordered).and_return( | 117 | Problem.should_receive(:ordered).and_return( |
| 118 | - mock('proxy', :paginate => errs) | 118 | + mock('proxy', :page => mock('other_proxy', :per => errs)) |
| 119 | ) | 119 | ) |
| 120 | get :all | 120 | get :all |
| 121 | assigns(:problems).should == errs | 121 | assigns(:problems).should == errs |
spec/controllers/users_controller_spec.rb
| @@ -100,7 +100,7 @@ describe UsersController do | @@ -100,7 +100,7 @@ describe UsersController do | ||
| 100 | @user.update_attribute :per_page, 2 | 100 | @user.update_attribute :per_page, 2 |
| 101 | users = 3.times { Factory(:user) } | 101 | users = 3.times { Factory(:user) } |
| 102 | get :index | 102 | get :index |
| 103 | - assigns(:users).size.should == 2 | 103 | + assigns(:users).to_a.size.should == 2 |
| 104 | end | 104 | end |
| 105 | end | 105 | end |
| 106 | 106 |
spec/factories/comment_factories.rb
spec/helpers/application_helper_spec.rb
| @@ -10,18 +10,3 @@ require 'spec_helper' | @@ -10,18 +10,3 @@ require 'spec_helper' | ||
| 10 | # end | 10 | # end |
| 11 | # end | 11 | # end |
| 12 | # end | 12 | # end |
| 13 | -describe ApplicationHelper do | ||
| 14 | - describe "get_host" do | ||
| 15 | - it "returns host if url is valid" do | ||
| 16 | - helper.get_host("http://example.com/resource/12").should == 'example.com' | ||
| 17 | - end | ||
| 18 | - | ||
| 19 | - it "returns 'N/A' when url is not valid" do | ||
| 20 | - helper.get_host("some string").should == 'N/A' | ||
| 21 | - end | ||
| 22 | - | ||
| 23 | - it "returns 'N/A' when url is empty" do | ||
| 24 | - helper.get_host({}).should == 'N/A' | ||
| 25 | - end | ||
| 26 | - end | ||
| 27 | -end |
spec/models/notice_spec.rb
| @@ -82,6 +82,36 @@ describe Notice do | @@ -82,6 +82,36 @@ describe Notice do | ||
| 82 | end | 82 | end |
| 83 | end | 83 | end |
| 84 | 84 | ||
| 85 | + describe "user agent string" do | ||
| 86 | + it "should be parsed and human-readable" do | ||
| 87 | + notice = Factory.build(:notice, :request => {'cgi-data' => {'HTTP_USER_AGENT' => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16'}}) | ||
| 88 | + notice.user_agent_string.should == 'Chrome 10.0.648.204' | ||
| 89 | + end | ||
| 90 | + | ||
| 91 | + it "should be nil if HTTP_USER_AGENT is blank" do | ||
| 92 | + notice = Factory.build(:notice) | ||
| 93 | + notice.user_agent_string.should == "N/A" | ||
| 94 | + end | ||
| 95 | + end | ||
| 96 | + | ||
| 97 | + describe "host" do | ||
| 98 | + it "returns host if url is valid" do | ||
| 99 | + notice = Factory.build(:notice, :request => {'url' => "http://example.com/resource/12"}) | ||
| 100 | + notice.host.should == 'example.com' | ||
| 101 | + end | ||
| 102 | + | ||
| 103 | + it "returns 'N/A' when url is not valid" do | ||
| 104 | + notice = Factory.build(:notice, :request => {'url' => "some string"}) | ||
| 105 | + notice.host.should == 'N/A' | ||
| 106 | + end | ||
| 107 | + | ||
| 108 | + it "returns 'N/A' when url is empty" do | ||
| 109 | + notice = Factory.build(:notice, :request => {}) | ||
| 110 | + notice.host.should == 'N/A' | ||
| 111 | + end | ||
| 112 | + | ||
| 113 | + end | ||
| 114 | + | ||
| 85 | 115 | ||
| 86 | describe "email notifications (configured individually for each app)" do | 116 | describe "email notifications (configured individually for each app)" do |
| 87 | custom_thresholds = [2, 4, 8, 16, 32, 64] | 117 | custom_thresholds = [2, 4, 8, 16, 32, 64] |
spec/models/problem_spec.rb
| @@ -197,5 +197,110 @@ describe Problem do | @@ -197,5 +197,110 @@ describe Problem do | ||
| 197 | }.should change(problem, :last_deploy_at).from(@last_deploy).to(next_deploy) | 197 | }.should change(problem, :last_deploy_at).from(@last_deploy).to(next_deploy) |
| 198 | end | 198 | end |
| 199 | end | 199 | end |
| 200 | + | ||
| 201 | + context "notice messages cache" do | ||
| 202 | + before do | ||
| 203 | + @app = Factory(:app) | ||
| 204 | + @problem = Factory(:problem, :app => @app) | ||
| 205 | + @err = Factory(:err, :problem => @problem) | ||
| 206 | + end | ||
| 207 | + | ||
| 208 | + it "#messages returns [] by default" do | ||
| 209 | + @problem.messages.should == [] | ||
| 210 | + end | ||
| 211 | + | ||
| 212 | + it "adding a notice adds a string to #messages" do | ||
| 213 | + lambda { | ||
| 214 | + Factory(:notice, :err => @err, :message => 'ERR 1') | ||
| 215 | + }.should change(@problem, :messages).from([]).to(['ERR 1']) | ||
| 216 | + end | ||
| 217 | + | ||
| 218 | + it "removing a notice removes string from #messages" do | ||
| 219 | + notice1 = Factory(:notice, :err => @err, :message => 'ERR 1') | ||
| 220 | + lambda { | ||
| 221 | + @err.notices.first.destroy | ||
| 222 | + @problem.reload | ||
| 223 | + }.should change(@problem, :messages).from(['ERR 1']).to([]) | ||
| 224 | + end | ||
| 225 | + end | ||
| 226 | + | ||
| 227 | + context "notice hosts cache" do | ||
| 228 | + before do | ||
| 229 | + @app = Factory(:app) | ||
| 230 | + @problem = Factory(:problem, :app => @app) | ||
| 231 | + @err = Factory(:err, :problem => @problem) | ||
| 232 | + end | ||
| 233 | + | ||
| 234 | + it "#hosts returns [] by default" do | ||
| 235 | + @problem.hosts.should == [] | ||
| 236 | + end | ||
| 237 | + | ||
| 238 | + it "adding a notice adds a string to #hosts" do | ||
| 239 | + lambda { | ||
| 240 | + Factory(:notice, :err => @err, :request => {'url' => "http://example.com/resource/12"}) | ||
| 241 | + }.should change(@problem, :hosts).from([]).to(['example.com']) | ||
| 242 | + end | ||
| 243 | + | ||
| 244 | + it "removing a notice removes string from #hosts" do | ||
| 245 | + notice1 = Factory(:notice, :err => @err, :request => {'url' => "http://example.com/resource/12"}) | ||
| 246 | + lambda { | ||
| 247 | + @err.notices.first.destroy | ||
| 248 | + @problem.reload | ||
| 249 | + }.should change(@problem, :hosts).from(['example.com']).to([]) | ||
| 250 | + end | ||
| 251 | + end | ||
| 252 | + | ||
| 253 | + context "notice user_agents cache" do | ||
| 254 | + before do | ||
| 255 | + @app = Factory(:app) | ||
| 256 | + @problem = Factory(:problem, :app => @app) | ||
| 257 | + @err = Factory(:err, :problem => @problem) | ||
| 258 | + end | ||
| 259 | + | ||
| 260 | + it "#user_agents returns [] by default" do | ||
| 261 | + @problem.user_agents.should == [] | ||
| 262 | + end | ||
| 263 | + | ||
| 264 | + it "adding a notice adds a string to #user_agents" do | ||
| 265 | + lambda { | ||
| 266 | + Factory(:notice, :err => @err, :request => {'cgi-data' => {'HTTP_USER_AGENT' => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16'}}) | ||
| 267 | + }.should change(@problem, :user_agents).from([]).to(['Chrome 10.0.648.204']) | ||
| 268 | + end | ||
| 269 | + | ||
| 270 | + it "removing a notice removes string from #user_agents" do | ||
| 271 | + notice1 = Factory(:notice, :err => @err, :request => {'cgi-data' => {'HTTP_USER_AGENT' => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.204 Safari/534.16'}}) | ||
| 272 | + lambda { | ||
| 273 | + @err.notices.first.destroy | ||
| 274 | + @problem.reload | ||
| 275 | + }.should change(@problem, :user_agents).from(['Chrome 10.0.648.204']).to([]) | ||
| 276 | + end | ||
| 277 | + end | ||
| 278 | + | ||
| 279 | + context "comment counter cache" do | ||
| 280 | + before do | ||
| 281 | + @app = Factory(:app) | ||
| 282 | + @problem = Factory(:problem, :app => @app) | ||
| 283 | + end | ||
| 284 | + | ||
| 285 | + it "#comments_count returns 0 by default" do | ||
| 286 | + @problem.comments_count.should == 0 | ||
| 287 | + end | ||
| 288 | + | ||
| 289 | + it "adding a comment increases #comments_count by 1" do | ||
| 290 | + lambda { | ||
| 291 | + Factory(:comment, :err => @problem) | ||
| 292 | + }.should change(@problem, :comments_count).from(0).to(1) | ||
| 293 | + end | ||
| 294 | + | ||
| 295 | + it "removing a comment decreases #comments_count by 1" do | ||
| 296 | + comment1 = Factory(:comment, :err => @problem) | ||
| 297 | + lambda { | ||
| 298 | + @problem.reload.comments.first.destroy | ||
| 299 | + @problem.reload | ||
| 300 | + }.should change(@problem, :comments_count).from(1).to(0) | ||
| 301 | + end | ||
| 302 | + end | ||
| 303 | + | ||
| 304 | + | ||
| 200 | end | 305 | end |
| 201 | 306 |
spec/views/errs/show.html.haml_spec.rb
| @@ -8,7 +8,7 @@ describe "errs/show.html.haml" do | @@ -8,7 +8,7 @@ describe "errs/show.html.haml" do | ||
| 8 | assign :problem, problem | 8 | assign :problem, problem |
| 9 | assign :comment, comment | 9 | assign :comment, comment |
| 10 | assign :app, problem.app | 10 | assign :app, problem.app |
| 11 | - assign :notices, err.notices.paginate(:page => 1, :per_page => 1) | 11 | + assign :notices, err.notices.page(1).per(1) |
| 12 | assign :notice, err.notices.first | 12 | assign :notice, err.notices.first |
| 13 | controller.stub(:current_user) { Factory(:user) } | 13 | controller.stub(:current_user) { Factory(:user) } |
| 14 | end | 14 | end |