rails_metrics 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/CHANGELOG.rdoc +3 -0
  2. data/Gemfile +9 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +58 -0
  5. data/Rakefile +58 -0
  6. data/TODO.rdoc +1 -0
  7. data/app/controllers/rails_metrics_controller.rb +78 -0
  8. data/app/helpers/rails_metrics_helper.rb +161 -0
  9. data/app/views/layouts/rails_metrics.html.erb +21 -0
  10. data/app/views/rails_metrics/_request.html.erb +21 -0
  11. data/app/views/rails_metrics/_row.html.erb +23 -0
  12. data/app/views/rails_metrics/all.html.erb +25 -0
  13. data/app/views/rails_metrics/chart.html.erb +49 -0
  14. data/app/views/rails_metrics/index.html.erb +21 -0
  15. data/app/views/rails_metrics/show.html.erb +41 -0
  16. data/config/routes.rb +7 -0
  17. data/lib/generators/rails_metrics_generator.rb +40 -0
  18. data/lib/rails_metrics.rb +112 -0
  19. data/lib/rails_metrics/async_consumer.rb +54 -0
  20. data/lib/rails_metrics/engine.rb +29 -0
  21. data/lib/rails_metrics/middleware.rb +27 -0
  22. data/lib/rails_metrics/orm/active_record.rb +66 -0
  23. data/lib/rails_metrics/payload_parser.rb +131 -0
  24. data/lib/rails_metrics/store.rb +132 -0
  25. data/lib/rails_metrics/version.rb +3 -0
  26. data/public/images/rails_metrics/arrow_down.png +0 -0
  27. data/public/images/rails_metrics/arrow_up.png +0 -0
  28. data/public/images/rails_metrics/cancel.png +0 -0
  29. data/public/images/rails_metrics/chart_pie.png +0 -0
  30. data/public/images/rails_metrics/page_white_delete.png +0 -0
  31. data/public/images/rails_metrics/page_white_go.png +0 -0
  32. data/public/images/rails_metrics/tick.png +0 -0
  33. data/public/javascripts/rails_metrics/g.pie-min.js +6 -0
  34. data/public/javascripts/rails_metrics/g.raphael-min.js +5 -0
  35. data/public/javascripts/rails_metrics/raphael-min.js +5 -0
  36. data/public/stylesheets/rails_metrics.css +135 -0
  37. data/test/dummy/app/controllers/application_controller.rb +4 -0
  38. data/test/dummy/app/controllers/users_controller.rb +43 -0
  39. data/test/dummy/app/helpers/application_helper.rb +2 -0
  40. data/test/dummy/app/models/metric.rb +3 -0
  41. data/test/dummy/app/models/notification.rb +7 -0
  42. data/test/dummy/app/models/user.rb +2 -0
  43. data/test/dummy/config/application.rb +52 -0
  44. data/test/dummy/config/boot.rb +9 -0
  45. data/test/dummy/config/environment.rb +5 -0
  46. data/test/dummy/config/environments/development.rb +19 -0
  47. data/test/dummy/config/environments/production.rb +33 -0
  48. data/test/dummy/config/environments/test.rb +29 -0
  49. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  50. data/test/dummy/config/initializers/cookie_verification_secret.rb +7 -0
  51. data/test/dummy/config/initializers/session_store.rb +15 -0
  52. data/test/dummy/config/routes.rb +60 -0
  53. data/test/dummy/db/migrate/20100106152343_create_metrics.rb +17 -0
  54. data/test/dummy/db/migrate/20100108120821_create_users.rb +13 -0
  55. data/test/integration/instrumentation_test.rb +100 -0
  56. data/test/integration/navigation_test.rb +103 -0
  57. data/test/orm/active_record_test.rb +51 -0
  58. data/test/payload_parser_test.rb +36 -0
  59. data/test/rails_metrics_test.rb +43 -0
  60. data/test/store_test.rb +81 -0
  61. data/test/support/helpers.rb +16 -0
  62. data/test/support/instrumentation.rb +18 -0
  63. data/test/support/mock_store.rb +34 -0
  64. data/test/support/webrat/integrations/rails.rb +31 -0
  65. data/test/test_helper.rb +32 -0
  66. metadata +118 -0
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,3 @@
1
+ class Metric < ActiveRecord::Base
2
+ include RailsMetrics::ORM::ActiveRecord
3
+ end
@@ -0,0 +1,7 @@
1
+ class Notification < ActionMailer::Base
2
+ def welcome
3
+ subject "Welcome"
4
+ from "sender@rails-metrics-app.com"
5
+ recipients "destination@rails-metrics-app.com"
6
+ end
7
+ end
@@ -0,0 +1,2 @@
1
+ class User < ActiveRecord::Base
2
+ end
@@ -0,0 +1,52 @@
1
+ require File.expand_path('../boot', __FILE__)
2
+
3
+ require "active_model/railtie"
4
+ require "active_record/railtie"
5
+ require "action_controller/railtie"
6
+ require "action_view/railtie"
7
+ require "action_mailer/railtie"
8
+
9
+ Bundler.require
10
+ require "rails_metrics"
11
+
12
+ module Dummy
13
+ class Application < Rails::Application
14
+ # Remove this in next release
15
+ config.root = File.expand_path("../..", __FILE__)
16
+
17
+ # Settings in config/environments/* take precedence over those specified here.
18
+ # Application configuration should go into files in config/initializers
19
+ # -- all .rb files in that directory are automatically loaded.
20
+
21
+ # Add additional load paths for your own custom dirs
22
+ # config.load_paths += %W( #{config.root}/extras )
23
+
24
+ # Only load the plugins named here, in the order given (default is alphabetical).
25
+ # :all can be used as a placeholder for all plugins not explicitly named
26
+ # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
27
+
28
+ # Activate observers that should always be running
29
+ # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
30
+
31
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
32
+ # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
33
+ # config.time_zone = 'Central Time (US & Canada)'
34
+
35
+ # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
36
+ # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
37
+ # config.i18n.default_locale = :de
38
+
39
+ # Configure generators values. Many other options are available, be sure to check the documentation.
40
+ config.generators do |g|
41
+ g.orm :active_record
42
+ g.template_engine :erb
43
+ g.test_framework false
44
+ end
45
+
46
+ # Reload engines
47
+ config.reload_engines = true
48
+
49
+ # Set RailsMetrics store.
50
+ config.rails_metrics.set_store = lambda { ::Metric }
51
+ end
52
+ end
@@ -0,0 +1,9 @@
1
+ begin
2
+ require File.expand_path("../../../../.bundle/environment", __FILE__)
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'bundler'
6
+ Bundler.setup
7
+ end
8
+
9
+ $:.unshift File.expand_path('../../../../lib', __FILE__)
@@ -0,0 +1,5 @@
1
+ # Load the rails application
2
+ require File.expand_path('../application', __FILE__)
3
+
4
+ # Initialize the rails application
5
+ Dummy::Application.initialize!
@@ -0,0 +1,19 @@
1
+ Dummy::Application.configure do
2
+ # Settings specified here will take precedence over those in config/environment.rb
3
+
4
+ # In the development environment your application's code is reloaded on
5
+ # every request. This slows down response time but is perfect for development
6
+ # since you don't have to restart the webserver when you make code changes.
7
+ config.cache_classes = false
8
+
9
+ # Log error messages when you accidentally call methods on nil.
10
+ config.whiny_nils = true
11
+
12
+ # Show full error reports and disable caching
13
+ config.consider_all_requests_local = true
14
+ config.action_view.debug_rjs = true
15
+ config.action_controller.perform_caching = false
16
+
17
+ # Don't care if the mailer can't send
18
+ config.action_mailer.raise_delivery_errors = false
19
+ end
@@ -0,0 +1,33 @@
1
+ Dummy::Application.configure do
2
+ # Settings specified here will take precedence over those in config/environment.rb
3
+
4
+ # The production environment is meant for finished, "live" apps.
5
+ # Code is not reloaded between requests
6
+ config.cache_classes = true
7
+
8
+ # Full error reports are disabled and caching is turned on
9
+ config.consider_all_requests_local = false
10
+ config.action_controller.perform_caching = true
11
+
12
+ # See everything in the log (default is :info)
13
+ # config.log_level = :debug
14
+
15
+ # Use a different logger for distributed setups
16
+ # config.logger = SyslogLogger.new
17
+
18
+ # Use a different cache store in production
19
+ # config.cache_store = :mem_cache_store
20
+
21
+ # Disable Rails's static asset server
22
+ # In production, Apache or nginx will already do this
23
+ config.serve_static_assets = false
24
+
25
+ # Enable serving of images, stylesheets, and javascripts from an asset server
26
+ # config.action_controller.asset_host = "http://assets.example.com"
27
+
28
+ # Disable delivery errors, bad email addresses will be ignored
29
+ # config.action_mailer.raise_delivery_errors = false
30
+
31
+ # Enable threaded mode
32
+ # config.threadsafe!
33
+ end
@@ -0,0 +1,29 @@
1
+ Dummy::Application.configure do
2
+ # Settings specified here will take precedence over those in config/environment.rb
3
+
4
+ # The test environment is used exclusively to run your application's
5
+ # test suite. You never need to work with it otherwise. Remember that
6
+ # your test database is "scratch space" for the test suite and is wiped
7
+ # and recreated between test runs. Don't rely on the data there!
8
+ config.cache_classes = true
9
+
10
+ # Log error messages when you accidentally call methods on nil.
11
+ config.whiny_nils = true
12
+
13
+ # Show full error reports and disable caching
14
+ config.consider_all_requests_local = true
15
+ config.action_controller.perform_caching = true
16
+
17
+ # Disable request forgery protection in test environment
18
+ config.action_controller.allow_forgery_protection = false
19
+
20
+ # Tell Action Mailer not to deliver emails to the real world.
21
+ # The :test delivery method accumulates sent emails in the
22
+ # ActionMailer::Base.deliveries array.
23
+ config.action_mailer.delivery_method = :test
24
+
25
+ # Use SQL instead of Active Record's schema dumper when creating the test database.
26
+ # This is necessary if your schema can't be completely dumped by the schema dumper,
27
+ # like if you have constraints or database-specific column types
28
+ # config.active_record.schema_format = :sql
29
+ end
@@ -0,0 +1,7 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
4
+ # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
5
+
6
+ # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
7
+ Rails.backtrace_cleaner.remove_silencers!
@@ -0,0 +1,7 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Your secret key for verifying the integrity of signed cookies.
4
+ # If you change this key, all old signed cookies will become invalid!
5
+ # Make sure the secret is at least 30 characters and all random,
6
+ # no regular words or you'll be exposed to dictionary attacks.
7
+ ActionController::Base.cookie_verifier_secret = 'db28d7ac0ee4317c045ec2efc0f073c2a0d03abfa90a1a2ea5b0eb5c0a50325792f79be6a0fb3797ec4376e4a9da3edf61dc85569a32e5dcb7e55148d6a49c5a'
@@ -0,0 +1,15 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Your secret key for verifying cookie session data integrity.
4
+ # If you change this key, all old sessions will become invalid!
5
+ # Make sure the secret is at least 30 characters and all random,
6
+ # no regular words or you'll be exposed to dictionary attacks.
7
+ ActionController::Base.session = {
8
+ :key => '_dummy_session',
9
+ :secret => '3bd151c2e33fc860c04c1deb5b9b456f800c6b737fc30f4bac49cb3363e3f806e8529e8b5d18fc324b4de08bc37b01b245f2cb380dbe43d5284438598ec35b3f'
10
+ }
11
+
12
+ # Use the database for sessions instead of the cookie-based default,
13
+ # which shouldn't be used to store highly confidential information
14
+ # (create the session table with "rake db:sessions:create")
15
+ # ActionController::Base.session_store = :active_record_store
@@ -0,0 +1,60 @@
1
+ Dummy::Application.routes.draw do |map|
2
+ resources :users
3
+
4
+ # The priority is based upon order of creation:
5
+ # first created -> highest priority.
6
+
7
+ # Sample of regular route:
8
+ # match 'products/:id' => 'catalog#view'
9
+ # Keep in mind you can assign values other than :controller and :action
10
+
11
+ # Sample of named route:
12
+ # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
13
+ # This route can be invoked with purchase_url(:id => product.id)
14
+
15
+ # Sample resource route (maps HTTP verbs to controller actions automatically):
16
+ # resources :products
17
+
18
+ # Sample resource route with options:
19
+ # resources :products do
20
+ # member do
21
+ # get :short
22
+ # post :toggle
23
+ # end
24
+ #
25
+ # collection do
26
+ # get :sold
27
+ # end
28
+ # end
29
+
30
+ # Sample resource route with sub-resources:
31
+ # resources :products do
32
+ # resources :comments, :sales
33
+ # resource :seller
34
+ # end
35
+
36
+ # Sample resource route with more complex sub-resources
37
+ # resources :products do
38
+ # resources :comments
39
+ # resources :sales do
40
+ # get :recent, :on => :collection
41
+ # end
42
+ # end
43
+
44
+ # Sample resource route within a namespace:
45
+ # namespace :admin do
46
+ # # Directs /admin/products/* to Admin::ProductsController
47
+ # # (app/controllers/admin/products_controller.rb)
48
+ # resources :products
49
+ # end
50
+
51
+ # You can have the root of your site routed with "root"
52
+ # just remember to delete public/index.html.
53
+ # root :to => "welcome#index"
54
+
55
+ # See how all your routes lay out with "rake routes"
56
+
57
+ # This is a legacy wild controller route that's not recommended for RESTful applications.
58
+ # Note: This route will make all actions in every controller accessible via GET requests.
59
+ # match ':controller(/:action(/:id(.:format)))'
60
+ end
@@ -0,0 +1,17 @@
1
+ class CreateMetrics < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :metrics do |t|
4
+ t.string :name
5
+ t.integer :request_id
6
+ t.integer :parent_id
7
+ t.integer :duration
8
+ t.text :payload
9
+ t.datetime :started_at
10
+ t.datetime :created_at
11
+ end
12
+ end
13
+
14
+ def self.down
15
+ drop_table :metrics
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ class CreateUsers < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :users do |t|
4
+ t.string :name
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+
10
+ def self.down
11
+ drop_table :users
12
+ end
13
+ end
@@ -0,0 +1,100 @@
1
+ require 'test_helper'
2
+
3
+ class InstrumentationTest < ActionController::IntegrationTest
4
+ setup do
5
+ Metric.delete_all
6
+ end
7
+
8
+ test "rails metrics request is added to notifications" do
9
+ get "/users"
10
+ wait
11
+
12
+ request = Metric.first
13
+
14
+ assert_equal "rack.request", request.name
15
+ assert (request.duration >= 0)
16
+ assert_kind_of Time, request.started_at
17
+ assert_equal Hash[:path => "/users", :method => "GET",
18
+ :instrumenter_id => ActiveSupport::Notifications.instrumenter.id], request.payload
19
+ end
20
+
21
+ test "processed actions are added to RailsMetrics" do
22
+ get "/users"
23
+ wait
24
+
25
+ assert_equal 4, Metric.count
26
+ request, action, sql, template = Metric.all
27
+
28
+ assert_equal "action_controller.process_action", action.name
29
+ assert_equal "active_record.sql", sql.name
30
+ assert_equal "action_view.render_template", template.name
31
+
32
+ assert (action.duration >= 0)
33
+ assert (sql.duration >= 0)
34
+ assert (template.duration >= 0)
35
+
36
+ assert_kind_of Time, action.started_at
37
+ assert_kind_of Time, sql.started_at
38
+ assert_kind_of Time, template.started_at
39
+
40
+ assert_equal Hash[:status=>200, :end_point=>"UsersController#index",
41
+ :formats=>[:html]], action.payload
42
+
43
+ assert_equal Hash[:sql => "SELECT `users`.* FROM `users`",
44
+ :name => "User Load"], sql.payload
45
+
46
+ assert_equal Hash[:identifier => "RAILS_ROOT/app/views/users/index.html.erb",
47
+ :layout => "RAILS_ROOT/app/views/layouts/users.html.erb"], template.payload
48
+ end
49
+
50
+ test "instrumentations are saved nested in the database" do
51
+ get "/users"
52
+ wait
53
+
54
+ assert_equal 4, Metric.count
55
+ request, action, sql, template = Metric.all
56
+
57
+ assert_nil request.parent_id
58
+ assert_equal action.parent_id, request.id
59
+ assert_equal sql.parent_id, action.id
60
+ assert_equal template.parent_id, action.id
61
+
62
+ assert_equal request.id, request.request_id
63
+ assert_equal request.id, action.request_id
64
+ assert_equal request.id, sql.request_id
65
+ assert_equal request.id, template.request_id
66
+ end
67
+
68
+ test "does not create metrics when accessing /rails_metrics" do
69
+ assert_no_difference "Metric.count" do
70
+ get "/rails_metrics"
71
+ wait
72
+ end
73
+ end
74
+
75
+ test "fragment cache are added to RailsMetrics" do
76
+ get "/users/new"
77
+ wait
78
+
79
+ assert_equal 6, Metric.count
80
+ request, action, template, partial, exist, write = Metric.all
81
+
82
+ assert_equal "action_view.render_partial", partial.name
83
+ assert_equal "action_controller.exist_fragment?", exist.name
84
+ assert_equal "action_controller.write_fragment", write.name
85
+
86
+ assert (partial.duration >= 0)
87
+ assert (exist.duration >= 0)
88
+ assert (write.duration >= 0)
89
+
90
+ assert_kind_of Time, partial.started_at
91
+ assert_kind_of Time, exist.started_at
92
+ assert_kind_of Time, write.started_at
93
+
94
+ assert_equal Hash[:identifier => "RAILS_ROOT/app/views/users/_form.html.erb"],
95
+ partial.payload
96
+
97
+ assert_equal Hash[:key => "views/foo.bar"], exist.payload
98
+ assert_equal Hash[:key => "views/foo.bar"], write.payload
99
+ end
100
+ end
@@ -0,0 +1,103 @@
1
+ require 'test_helper'
2
+
3
+ class NagivationTest < ActionController::IntegrationTest
4
+ setup do
5
+ Metric.delete_all
6
+ get "/users"
7
+ wait
8
+ end
9
+
10
+ test "can navigate all notifications" do
11
+ get "/rails_metrics"
12
+ click_link "All metrics"
13
+
14
+ assert_contain "action_view.render_template"
15
+ assert_contain "action_controller.process_action"
16
+ assert_contain ActiveSupport::Notifications.instrumenter.id
17
+
18
+ id = Metric.last.id
19
+
20
+ within "#rails_metric_#{id}" do
21
+ click_link "Show"
22
+ end
23
+
24
+ assert_contain "action_view.render_template"
25
+ click_link "action_view.render_template"
26
+
27
+ within "#rails_metric_#{id}" do
28
+ click_button "Delete"
29
+ end
30
+
31
+ assert_contain "Metric ##{id} was deleted with success"
32
+
33
+ get "/rails_metrics/all"
34
+ assert_not_contain "action_view.render_template"
35
+ end
36
+
37
+ test "can nagivate all metrics with by scopes" do
38
+ get "/rails_metrics/all"
39
+
40
+ click_link "active_record.sql"
41
+ assert_contain "Showing 1 - 1 of 1 metrics filtered by name"
42
+
43
+ click_link "Remove \"Name\" filter"
44
+ assert_contain "Showing 1 - 4 of 4 metrics"
45
+ end
46
+
47
+ test "can nagivate all metrics with order by scopes" do
48
+ get "/rails_metrics/all"
49
+ click_link "Order by latest"
50
+ assert_contain "ordered by latest"
51
+
52
+ click_link "Show"
53
+ assert_contain "action_view.render_template"
54
+
55
+ click_link "Back"
56
+ click_link "Order by earliest"
57
+ assert_contain "ordered by earliest"
58
+
59
+ click_link "Show"
60
+ assert_contain "rack.request"
61
+
62
+ click_link "Back"
63
+ click_link "Order by fastest"
64
+ assert_contain "ordered by fastest"
65
+
66
+ click_link "Show"
67
+ assert_contain Metric.fastest.first.name
68
+ end
69
+
70
+ test "can destroy all notifications in a given scope" do
71
+ get "/rails_metrics/all"
72
+ click_link "active_record.sql"
73
+ assert_contain "Showing 1 - 1 of 1 metrics filtered by name"
74
+
75
+ click_button "Delete all"
76
+ assert_contain "All 1 selected metrics were deleted."
77
+
78
+ click_link "All metrics"
79
+ assert_contain "Showing 1 - 3 of 3 metrics"
80
+ end
81
+
82
+ test "can navigate all metrics with pagination" do
83
+ get "/rails_metrics/all"
84
+ assert_contain "Showing 1 - 4 of 4 metrics"
85
+
86
+ get "/rails_metrics/all?limit=2"
87
+ assert_contain "Showing 1 - 2 of 4 metrics"
88
+
89
+ click_link "Next"
90
+ assert_contain "Showing 3 - 4 of 4 metrics"
91
+
92
+ assert_raise Webrat::NotFoundError do
93
+ click_link "Next"
94
+ end
95
+
96
+ click_link "Previous"
97
+ assert_contain "Showing 1 - 2 of 4 metrics"
98
+
99
+ assert_raise Webrat::NotFoundError do
100
+ click_link "Previous"
101
+ end
102
+ end
103
+ end