rscratch 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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