rscratch 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +15 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +99 -0
  4. data/Rakefile +40 -0
  5. data/app/assets/javascripts/rscratch/Chart.min.js +11 -0
  6. data/app/assets/javascripts/rscratch/application.js +128 -0
  7. data/app/assets/javascripts/rscratch/dashboard.js +90 -0
  8. data/app/assets/javascripts/rscratch/exceptions.js +97 -0
  9. data/app/assets/javascripts/rscratch/templates/exception_overview.jst.ejs +57 -0
  10. data/app/assets/javascripts/rscratch/templates/loader.jst.ejs +65 -0
  11. data/app/assets/stylesheets/rscratch/application.css +13 -0
  12. data/app/assets/stylesheets/rscratch/style.css +101 -0
  13. data/app/controllers/rscratch/application_controller.rb +12 -0
  14. data/app/controllers/rscratch/dashboard_controller.rb +13 -0
  15. data/app/controllers/rscratch/exceptions_controller.rb +23 -0
  16. data/app/helpers/rscratch/application_helper.rb +4 -0
  17. data/app/helpers/rscratch/dashboard_helper.rb +4 -0
  18. data/app/helpers/rscratch/exceptions_helper.rb +4 -0
  19. data/app/models/rscratch/exception.rb +68 -0
  20. data/app/models/rscratch/exception_log.rb +49 -0
  21. data/app/views/layouts/rscratch/application.html.haml +35 -0
  22. data/app/views/rscratch/dashboard/index.html.haml +12 -0
  23. data/app/views/rscratch/exceptions/_exception_smartlist.html.haml +21 -0
  24. data/app/views/rscratch/exceptions/index.html.haml +59 -0
  25. data/app/views/rscratch/exceptions/index.js.erb +3 -0
  26. data/app/views/rscratch/exceptions/show.json.jbuilder +13 -0
  27. data/app/views/smart_listing/_action_custom.html.erb +10 -0
  28. data/app/views/smart_listing/_action_delete.html.erb +12 -0
  29. data/app/views/smart_listing/_action_edit.html.erb +11 -0
  30. data/app/views/smart_listing/_action_show.html.erb +11 -0
  31. data/app/views/smart_listing/_item_new.html.erb +30 -0
  32. data/app/views/smart_listing/_pagination_per_page_link.html.erb +12 -0
  33. data/app/views/smart_listing/_pagination_per_page_links.html.erb +19 -0
  34. data/app/views/smart_listing/_sortable.html.erb +21 -0
  35. data/config/routes.rb +8 -0
  36. data/db/migrate/20160123064059_create_rscratch_exceptions.rb +15 -0
  37. data/db/migrate/20160123064828_create_rscratch_exception_logs.rb +17 -0
  38. data/lib/generators/rscratch/install/install_generator.rb +27 -0
  39. data/lib/generators/rscratch/install/templates/initializer.rb.erb +7 -0
  40. data/lib/generators/rscratch/install/templates/migration.rb +40 -0
  41. data/lib/rscratch.rb +11 -0
  42. data/lib/rscratch/configuration.rb +7 -0
  43. data/lib/rscratch/engine.rb +10 -0
  44. data/lib/rscratch/version.rb +3 -0
  45. data/lib/tasks/rscratch_tasks.rake +4 -0
  46. data/test/dummy/README.rdoc +261 -0
  47. data/test/dummy/Rakefile +7 -0
  48. data/test/dummy/app/assets/javascripts/application.js +15 -0
  49. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  50. data/test/dummy/app/controllers/application_controller.rb +3 -0
  51. data/test/dummy/app/helpers/application_helper.rb +2 -0
  52. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  53. data/test/dummy/config.ru +4 -0
  54. data/test/dummy/config/application.rb +59 -0
  55. data/test/dummy/config/boot.rb +10 -0
  56. data/test/dummy/config/database.yml +25 -0
  57. data/test/dummy/config/environment.rb +5 -0
  58. data/test/dummy/config/environments/development.rb +37 -0
  59. data/test/dummy/config/environments/production.rb +67 -0
  60. data/test/dummy/config/environments/test.rb +37 -0
  61. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  62. data/test/dummy/config/initializers/inflections.rb +15 -0
  63. data/test/dummy/config/initializers/mime_types.rb +5 -0
  64. data/test/dummy/config/initializers/secret_token.rb +7 -0
  65. data/test/dummy/config/initializers/session_store.rb +8 -0
  66. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  67. data/test/dummy/config/locales/en.yml +5 -0
  68. data/test/dummy/config/routes.rb +4 -0
  69. data/test/dummy/public/404.html +26 -0
  70. data/test/dummy/public/422.html +26 -0
  71. data/test/dummy/public/500.html +25 -0
  72. data/test/dummy/public/favicon.ico +0 -0
  73. data/test/dummy/script/rails +6 -0
  74. data/test/fixtures/rscratch/exception_logs.yml +23 -0
  75. data/test/fixtures/rscratch/exceptions.yml +19 -0
  76. data/test/functional/rscratch/dashboard_controller_test.rb +11 -0
  77. data/test/functional/rscratch/exceptions_controller_test.rb +11 -0
  78. data/test/integration/navigation_test.rb +10 -0
  79. data/test/rscratch_test.rb +7 -0
  80. data/test/test_helper.rb +15 -0
  81. data/test/unit/helpers/rscratch/dashboard_helper_test.rb +6 -0
  82. data/test/unit/helpers/rscratch/exceptions_helper_test.rb +6 -0
  83. data/test/unit/rscratch/exception_log_test.rb +9 -0
  84. data/test/unit/rscratch/exception_test.rb +9 -0
  85. metadata +235 -0
@@ -0,0 +1,57 @@
1
+ <%
2
+
3
+ var entityMap = {
4
+ "&": "&amp;",
5
+ "<": "&lt;",
6
+ ">": "&gt;",
7
+ '"': '&quot;',
8
+ "'": '&#39;',
9
+ "/": '&#x2F;'
10
+ };
11
+ function escapeHtml(string) {
12
+ return String(string).replace(/[&<>"'\/]/g, function (s) {
13
+ return entityMap[s];
14
+ });
15
+ }
16
+ var created_at = new Date(response.created_at);
17
+ var created_at = created_at.format("dd-mm-yyyy hh:MM TT","GMT");
18
+
19
+ var updated_at = new Date(response.updated_at);
20
+ var updated_at = updated_at.format("dd-mm-yyyy hh:MM TT","GMT");
21
+ %>
22
+ <div class="row">
23
+ <div class="col s3">First seen at</div>
24
+ <div class="col s9"><%= created_at %></div>
25
+ </div>
26
+ <div class="row">
27
+ <div class="col s3">Last seen at</div>
28
+ <div class="col s9"><%= updated_at %></div>
29
+ </div>
30
+ <div class="row">
31
+ <div class="col s3">Occurrences</div>
32
+ <div class="col s9"><%= response.total_occurance_count %></div>
33
+ </div>
34
+ <div class="row">
35
+ <div class="col s3">Description</div>
36
+ <div class="col s9"> <%= escapeHtml(response.log.description) %></div>
37
+ </div>
38
+ <div class="row">
39
+ <div class="col s3">Environment</div>
40
+ <div class="col s9"><%= response.app_environment %></div>
41
+ </div>
42
+ <div class="row">
43
+ <div class="col s3">Request URL</div>
44
+ <div class="col s9"><%= response.log.request_url %></div>
45
+ </div>
46
+ <div class="row">
47
+ <div class="col s3">Request Method</div>
48
+ <div class="col s9"><%= response.log.request_method %></div>
49
+ </div>
50
+ <div class="row">
51
+ <div class="col s3">Client IP</div>
52
+ <div class="col s9"><%= response.log.client_ip %></div>
53
+ </div>
54
+ <div class="row">
55
+ <div class="col s3">User Agent</div>
56
+ <div class="col s9"><%= response.log.user_agent %></div>
57
+ </div>
@@ -0,0 +1,65 @@
1
+ <center>
2
+ <% if (typeof loader_type != 'undefined') {%>
3
+ <% if(loader_type == "progressbar") { %>
4
+ <div class="m-progress">
5
+ <div class="indeterminate"></div>
6
+ </div>
7
+ <% } else { if(loader_type == "blue-spinner") {%>
8
+ <div class="preloader-wrapper active" style="margin:40px">
9
+ <div class="spinner-layer spinner-blue-only">
10
+ <div class="circle-clipper left">
11
+ <div class="circle"></div>
12
+ </div><div class="gap-patch">
13
+ <div class="circle"></div>
14
+ </div><div class="circle-clipper right">
15
+ <div class="circle"></div>
16
+ </div>
17
+ </div>
18
+ </div>
19
+
20
+ <% } %>
21
+ <% } %>
22
+ <% } else { %>
23
+ <div class="preloader-wrapper active" style="margin:40px; margin-top:80px">
24
+ <div class="spinner-layer spinner-blue">
25
+ <div class="circle-clipper left">
26
+ <div class="circle"></div>
27
+ </div><div class="gap-patch">
28
+ <div class="circle"></div>
29
+ </div><div class="circle-clipper right">
30
+ <div class="circle"></div>
31
+ </div>
32
+ </div>
33
+
34
+ <div class="spinner-layer spinner-red">
35
+ <div class="circle-clipper left">
36
+ <div class="circle"></div>
37
+ </div><div class="gap-patch">
38
+ <div class="circle"></div>
39
+ </div><div class="circle-clipper right">
40
+ <div class="circle"></div>
41
+ </div>
42
+ </div>
43
+
44
+ <div class="spinner-layer spinner-yellow">
45
+ <div class="circle-clipper left">
46
+ <div class="circle"></div>
47
+ </div><div class="gap-patch">
48
+ <div class="circle"></div>
49
+ </div><div class="circle-clipper right">
50
+ <div class="circle"></div>
51
+ </div>
52
+ </div>
53
+
54
+ <div class="spinner-layer spinner-green">
55
+ <div class="circle-clipper left">
56
+ <div class="circle"></div>
57
+ </div><div class="gap-patch">
58
+ <div class="circle"></div>
59
+ </div><div class="circle-clipper right">
60
+ <div class="circle"></div>
61
+ </div>
62
+ </div>
63
+ </div>
64
+ <% } %>
65
+ </center>
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,101 @@
1
+ h1.logo-wrapper {
2
+ margin: 0px 30px 0px 0px;
3
+ overflow-y:hidden;
4
+ }
5
+ h1.logo-wrapper a {
6
+ display: inline;
7
+ }
8
+ h1.logo-wrapper a:hover{
9
+ background-color: #FFF;
10
+ }
11
+ header .brand-logo {
12
+ margin: 1px 0px;
13
+ padding: 0px 20px;
14
+ }
15
+ header .brand-logo img {
16
+ width: 172px;
17
+ }
18
+ h1 span.logo-text {
19
+ display: none;
20
+ }
21
+ .p0{ padding: 0px !important; }
22
+ .p5{ padding: 5px !important; }
23
+ .p10{ padding: 10px !important; }
24
+ .p20{ padding: 20px; }
25
+
26
+ .margin-t-0{ margin-top:0px !important; }
27
+ .margin-t-5{ margin-top:5px !important; }
28
+ .margin-0{ margin:0px !important; }
29
+
30
+ .font-10{ font-size: 10px; }
31
+ .font-11{ font-size: 11px; }
32
+ .font-12{ font-size: 12px; }
33
+ .font-14{ font-size: 14px; }
34
+ .font-16{ font-size: 16px !important; }
35
+ .font-18{ font-size: 18px !important; }
36
+ .font-20{ font-size: 20px !important; }
37
+ .font-24{ font-size: 24px !important; }
38
+ .font-34{ font-size: 34px !important; }
39
+
40
+ .font-weight-300{ font-weight: 300 !important; }
41
+
42
+ .min-height-70{ min-height: 70px !important; }
43
+
44
+ .fixed-sidebar{
45
+ position: fixed;
46
+ height: calc(100% - 50px);
47
+ overflow-y:auto;
48
+ width:inherit
49
+ }
50
+
51
+ span.badge {
52
+ font-weight: 300;
53
+ font-size: 0.8rem;
54
+ color: #FFF;
55
+ background-color: #26A69A;
56
+ border-radius: 2px;
57
+ }
58
+
59
+ span.label {
60
+ font-weight: 300;
61
+ font-size: 0.8rem;
62
+ color: #FFF;
63
+ background-color: #26A69A;
64
+ border-radius: 2px;
65
+ padding: 1px 6px;
66
+ line-height: inherit;
67
+ }
68
+
69
+ .width-100{ width: 100%; }
70
+
71
+ .border-radius-0{border-radius: 0px !important;}
72
+ .collection .collection-item {
73
+ border-right: 4px solid #FFFFFF;
74
+ padding: 5px 20px;
75
+ }
76
+ .collection .collection-item.selected {
77
+ background: #E1F5FE none repeat scroll 0% 0%;
78
+ border-right: 4px solid #29B6F6;
79
+ }
80
+
81
+ .tabs .indicator {
82
+ position: absolute;
83
+ bottom: 0;
84
+ height: 2px;
85
+ background-color: #b2ebf2 !important;
86
+ will-change: left, right; }
87
+ #log-page-header .card-image {
88
+ height: 250px;
89
+ }
90
+ #log-page-header .card-content {
91
+ margin-top: -30px;
92
+ }
93
+ #log-page-header .card-profile-image {
94
+ width: 110px;
95
+ position: absolute;
96
+ top: 190px;
97
+ z-index: 1;
98
+ left: 40px;
99
+ cursor: pointer;
100
+ margin: 0px;
101
+ }
@@ -0,0 +1,12 @@
1
+ module Rscratch
2
+ class ApplicationController < ActionController::Base
3
+ before_filter :authenticate
4
+
5
+ def authenticate
6
+ if Rscratch.configuration.authenticate
7
+ instance_eval(&Rscratch.configuration.authenticate)
8
+ end
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ require_dependency "rscratch/application_controller"
2
+
3
+ module Rscratch
4
+ class DashboardController < ApplicationController
5
+ def index
6
+ @activity_log = Rscratch::ExceptionLog.select("count(id) as exception_count, date(created_at) as date").group("date(created_at)").order("date(created_at)").last(30)
7
+ respond_to do |format|
8
+ format.html # index.html.erb
9
+ format.json { render json: @activity_log }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ require_dependency "rscratch/application_controller"
2
+ module Rscratch
3
+ class ExceptionsController < ApplicationController
4
+ include SmartListing::Helper::ControllerExtensions
5
+ helper SmartListing::Helper
6
+ def index
7
+ @exceptions = Rscratch::Exception.order("updated_at desc")
8
+ smart_listing_create :exceptions, @exceptions.by_status('new'), partial: "rscratch/exceptions/exception_smartlist"
9
+ smart_listing_create :resolved_exceptions, @exceptions.by_status('resolved'), partial: "rscratch/exceptions/exception_smartlist"
10
+ respond_to do |format|
11
+ format.html # index.html.erb
12
+ format.js
13
+ format.json { render json: @exceptions }
14
+ end
15
+ end
16
+ def show
17
+ @excp = Rscratch::Exception.find(params[:id])
18
+ @log = @excp.exception_logs.order("created_at desc").page(params[:page]).per(1)
19
+ @historical_data = @excp.exception_logs.select("count(id) as exception_count, date(created_at) as date").group("date(created_at)").order("date(created_at)").last(30)
20
+ rescue Exception => @error
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,4 @@
1
+ module Rscratch
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Rscratch
2
+ module DashboardHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Rscratch
2
+ module ExceptionsHelper
3
+ end
4
+ end
@@ -0,0 +1,68 @@
1
+ module Rscratch
2
+ class Exception < ActiveRecord::Base
3
+
4
+ if Rails::VERSION::MAJOR == 3
5
+ attr_accessible :action, :app_environment, :controller, :exception, :message, :new_occurance_count, :total_occurance_count, :status
6
+ end
7
+
8
+ STATUS = %w(new under_development resolved)
9
+
10
+ ### => Model Relations
11
+ has_many :exception_logs, :dependent => :destroy
12
+
13
+ ### => Model Validations
14
+ validates :exception , presence: true
15
+ validates :message , presence: true
16
+ validates :controller , presence: true
17
+ validates :action , presence: true
18
+ validates :app_environment , presence: true
19
+ validates :status , presence: true, :inclusion => {:in => STATUS}
20
+
21
+ ### => Model Scopes
22
+ scope :by_exception, lambda {|exc|where(["exception=?", exc])}
23
+ scope :by_message, lambda {|msg|where(["message=?", msg])}
24
+ scope :by_controller, lambda {|con|where(["controller=?", con])}
25
+ scope :by_action, lambda {|act|where(["action=?", act])}
26
+ scope :by_environment, lambda {|env|where(["app_environment=?", env])}
27
+ scope :by_status, lambda {|status|where(["status=?", status])}
28
+
29
+ # => Dynamic methods for exception statuses
30
+ STATUS.each do |status|
31
+ define_method "#{status}?" do
32
+ self.status == status
33
+ end
34
+ end
35
+
36
+ # Log an exception
37
+ def self.log(exc,request)
38
+ _exception = self.find_or_add_exception(exc,request.filtered_parameters["controller"].camelize,request.filtered_parameters["action"],Rails.env.camelize)
39
+ _excp_log = ExceptionLog.new(
40
+ :description => exc.inspect,
41
+ :backtrace => exc.backtrace.join("\n"),
42
+ :request_url => request.original_url,
43
+ :request_method => request.request_method,
44
+ :parameters => request.filtered_parameters,
45
+ :user_agent => request.user_agent,
46
+ :client_ip => request.remote_ip,
47
+ :status => "new")
48
+ _exception.exception_logs << _excp_log
49
+ return _exception
50
+ end
51
+
52
+ # Log unique exceptions
53
+ def self.find_or_add_exception exc,_controller,_action,_env
54
+ _excp = Exception.by_exception(exc.class).by_message(exc.message).by_controller(_controller).by_action(_action).by_environment(_env)
55
+ if _excp.present?
56
+ return _excp.first
57
+ else
58
+ _new_excp = Exception.create( :exception => exc.class,
59
+ :message => exc.message,
60
+ :controller => _controller,
61
+ :action => _action,
62
+ :app_environment => _env,
63
+ :status => "new")
64
+ return _new_excp
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,49 @@
1
+ module Rscratch
2
+ class ExceptionLog < ActiveRecord::Base
3
+
4
+ if Rails::VERSION::MAJOR == 3
5
+ attr_accessible :backtrace, :client_ip, :description, :exception_id, :parameters, :request_method, :request_url, :status, :user_agent
6
+ end
7
+ ### => Model Relations
8
+ belongs_to :exception
9
+
10
+ ### => Defining statuses
11
+ STATUS = %w(new under_development resolved)
12
+
13
+ ### => Model Validations
14
+ validates :exception_id, presence: true
15
+ validates :status, presence: true, :inclusion => {:in => STATUS}
16
+
17
+ ### => Model Callbacks
18
+ after_create :calculate_exception_count
19
+
20
+ # => Dynamic methods for log statuses
21
+ STATUS.each do |status|
22
+ define_method "#{status}?" do
23
+ self.status == status
24
+ end
25
+ end
26
+
27
+ ### => Model Scopes
28
+ scope :by_exception, lambda {|exc_id|where(["exception_id=?", exc_id])}
29
+ scope :unresolved_exceptions, lambda {|last_id|where(["id >?", last_id])}
30
+ scope :resolved, lambda {where(["status=?", "resolved"])}
31
+
32
+ def development!
33
+ update_attribute(:status, 'under_development')
34
+ end
35
+
36
+ def resolve!
37
+ update_attribute(:status, 'resolved')
38
+ end
39
+
40
+ private
41
+
42
+ def calculate_exception_count
43
+ _exception_logs = ExceptionLog.by_exception(self.exception_id)
44
+ _last_resolved = _exception_logs.resolved.last
45
+ _new_logs = _last_resolved.present? ? (ExceptionLog.unresolved_exceptions(_last_resolved.id)) : _exception_logs
46
+ self.exception.update_attributes(:total_occurance_count=>_exception_logs.count, :new_occurance_count=>_new_logs.count)
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,35 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title Rscratch | Track Exceptions and Bugs of your Rails application
5
+ / Import Google Icon Font
6
+ %link{:href => "http://fonts.googleapis.com/icon?family=Material+Icons", :rel => "stylesheet"}
7
+ / Import materialize.css
8
+ %link{:href => "https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/css/materialize.min.css", :rel => "stylesheet"}
9
+ / Compiled and minified JavaScript
10
+ = stylesheet_link_tag "rscratch/application", :media => "all"
11
+ = javascript_include_tag "rscratch/application"
12
+ %script{:src => "https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.5/js/materialize.min.js"}
13
+ = csrf_meta_tags
14
+ %body
15
+ .navbar-fixed
16
+ %nav.white
17
+ .nav-wrapper
18
+ %ul.left
19
+ %li
20
+ %h1.logo-wrapper{:style => ""}
21
+ %a{:href => "/rscratch"}
22
+ %img{:alt => "Rscratch", :height => "55", :src => "http://rscratch.github.io/rscratch_logo.png"}
23
+ %span.logo-text RScratch
24
+ %ul#nav-mobile.left.hide-on-med-and-down.grey-text
25
+ %li{:class => "#{'active' if current_page?(root_path)}"}
26
+ %a.grey-text.text-darken-2{:href => root_path} DASHBOARD
27
+ %li{:class => "#{'active' if current_page?(exceptions_path)}"}
28
+ %a.grey-text.text-darken-2{:href => exceptions_path} EXCEPTIONS
29
+ / %li
30
+ / %a.grey-text.text-darken-2{:href => "#"} CONFIGURATIONS
31
+ %ul.right.hide-on-med-and-down
32
+ %li
33
+ %a.waves-effect.waves-light.btn.green.darken-1{:href => "https://github.com/avishekjana/rscratch", :target => "_blank"}
34
+ Fork on Github
35
+ = yield