rails_live_dashboard 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +63 -0
  4. data/Rakefile +8 -0
  5. data/app/assets/builds/rails_live_dashboard/application.css +1 -0
  6. data/app/assets/builds/rails_live_dashboard/application.js +39 -0
  7. data/app/assets/builds/rails_live_dashboard/application.js.map +7 -0
  8. data/app/assets/javascripts/rails_live_dashboard/application.js +2 -0
  9. data/app/assets/javascripts/rails_live_dashboard/controllers/application.js +9 -0
  10. data/app/assets/javascripts/rails_live_dashboard/controllers/index.js +6 -0
  11. data/app/assets/javascripts/rails_live_dashboard/controllers/reveal_controller.js +28 -0
  12. data/app/assets/javascripts/rails_live_dashboard/controllers/tabs_controller.js +37 -0
  13. data/app/assets/stylesheets/rails_live_dashboard/application.css +5 -0
  14. data/app/components/rails_live_dashboard/query_duration_badge_component.html.erb +3 -0
  15. data/app/components/rails_live_dashboard/query_duration_badge_component.rb +27 -0
  16. data/app/components/rails_live_dashboard/request_duration_badge_component.html.erb +3 -0
  17. data/app/components/rails_live_dashboard/request_duration_badge_component.rb +27 -0
  18. data/app/components/rails_live_dashboard/request_method_badge_component.html.erb +6 -0
  19. data/app/components/rails_live_dashboard/request_method_badge_component.rb +24 -0
  20. data/app/components/rails_live_dashboard/request_status_badge_component.html.erb +3 -0
  21. data/app/components/rails_live_dashboard/request_status_badge_component.rb +22 -0
  22. data/app/controllers/rails_live_dashboard/application_controller.rb +4 -0
  23. data/app/controllers/rails_live_dashboard/clean_controller.rb +9 -0
  24. data/app/controllers/rails_live_dashboard/dashboard_controller.rb +8 -0
  25. data/app/controllers/rails_live_dashboard/exceptions_controller.rb +13 -0
  26. data/app/controllers/rails_live_dashboard/queries_controller.rb +11 -0
  27. data/app/controllers/rails_live_dashboard/requests_controller.rb +13 -0
  28. data/app/controllers/rails_live_dashboard/widgets/slowest_queries_controller.rb +11 -0
  29. data/app/controllers/rails_live_dashboard/widgets/slowest_requests_controller.rb +11 -0
  30. data/app/helpers/rails_live_dashboard/application_helper.rb +4 -0
  31. data/app/helpers/rails_live_dashboard/clean_helper.rb +4 -0
  32. data/app/helpers/rails_live_dashboard/dashboard_helper.rb +4 -0
  33. data/app/helpers/rails_live_dashboard/exceptions_helper.rb +4 -0
  34. data/app/helpers/rails_live_dashboard/requests_helper.rb +4 -0
  35. data/app/jobs/rails_live_dashboard/application_job.rb +4 -0
  36. data/app/mailers/rails_live_dashboard/application_mailer.rb +6 -0
  37. data/app/models/rails_live_dashboard/application_record.rb +5 -0
  38. data/app/models/rails_live_dashboard/entry.rb +5 -0
  39. data/app/models/rails_live_dashboard/exception.rb +31 -0
  40. data/app/models/rails_live_dashboard/query.rb +5 -0
  41. data/app/models/rails_live_dashboard/request.rb +45 -0
  42. data/app/models/rails_live_dashboard/types/content.rb +32 -0
  43. data/app/models/rails_live_dashboard/types/exception_content.rb +42 -0
  44. data/app/models/rails_live_dashboard/types/query_content.rb +42 -0
  45. data/app/models/rails_live_dashboard/types/request_content.rb +49 -0
  46. data/app/views/layouts/rails_live_dashboard/application.html.erb +18 -0
  47. data/app/views/rails_live_dashboard/dashboard/show.html.erb +27 -0
  48. data/app/views/rails_live_dashboard/exceptions/_tabs.html.erb +16 -0
  49. data/app/views/rails_live_dashboard/exceptions/index.html.erb +55 -0
  50. data/app/views/rails_live_dashboard/exceptions/show.html.erb +41 -0
  51. data/app/views/rails_live_dashboard/queries/_list.html.erb +43 -0
  52. data/app/views/rails_live_dashboard/queries/index.html.erb +11 -0
  53. data/app/views/rails_live_dashboard/queries/show.html.erb +33 -0
  54. data/app/views/rails_live_dashboard/requests/_contents.html.erb +26 -0
  55. data/app/views/rails_live_dashboard/requests/_exceptions.html.erb +43 -0
  56. data/app/views/rails_live_dashboard/requests/_queries.html.erb +11 -0
  57. data/app/views/rails_live_dashboard/requests/_relateds.html.erb +23 -0
  58. data/app/views/rails_live_dashboard/requests/index.html.erb +48 -0
  59. data/app/views/rails_live_dashboard/requests/show.html.erb +46 -0
  60. data/app/views/rails_live_dashboard/shared/_header.html.erb +43 -0
  61. data/app/views/rails_live_dashboard/widgets/slowest_queries/show.html.erb +42 -0
  62. data/app/views/rails_live_dashboard/widgets/slowest_requests/show.html.erb +42 -0
  63. data/config/routes.rb +14 -0
  64. data/db/migrate/20240213133517_create_rails_live_dashboard_entries.rb +14 -0
  65. data/lib/generators/rails_live_dashboard/install_generator.rb +11 -0
  66. data/lib/generators/templates/initializer.rb +3 -0
  67. data/lib/rails_live_dashboard/configuration.rb +13 -0
  68. data/lib/rails_live_dashboard/context.rb +19 -0
  69. data/lib/rails_live_dashboard/engine.rb +28 -0
  70. data/lib/rails_live_dashboard/recorders/exception_recorder.rb +42 -0
  71. data/lib/rails_live_dashboard/recorders/query_recorder.rb +30 -0
  72. data/lib/rails_live_dashboard/recorders/request_recorder.rb +30 -0
  73. data/lib/rails_live_dashboard/subscribers/action_controller_subscriber.rb +28 -0
  74. data/lib/rails_live_dashboard/subscribers/active_record_subscriber.rb +23 -0
  75. data/lib/rails_live_dashboard/version.rb +3 -0
  76. data/lib/rails_live_dashboard.rb +19 -0
  77. data/lib/tasks/rails_live_dashboard_tasks.rake +4 -0
  78. metadata +136 -0
@@ -0,0 +1,19 @@
1
+ require 'singleton'
2
+
3
+ module RailsLiveDashboard
4
+ class Context
5
+ include Singleton
6
+
7
+ def start
8
+ @batch_id = SecureRandom.uuid
9
+ end
10
+
11
+ def batch_id
12
+ @batch_id ||= SecureRandom.uuid
13
+ end
14
+
15
+ def reset
16
+ @batch_id = nil
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ module RailsLiveDashboard
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace RailsLiveDashboard
4
+
5
+ initializer 'rails_live_dashboard', after: :load_config_initializers do |_app|
6
+ next unless RailsLiveDashboard.configuration.enabled
7
+ end
8
+
9
+ initializer 'rails_live_dashboard.assets.precompile' do |app|
10
+ next unless RailsLiveDashboard.configuration.enabled
11
+
12
+ app.config.assets.precompile += [
13
+ 'builds/rails_live_dashboard/application.js',
14
+ 'builds/rails_live_dashboard/application.css'
15
+ ]
16
+ end
17
+
18
+ initializer 'rails_live_dashboard.action_controller' do
19
+ next unless RailsLiveDashboard.configuration.enabled
20
+
21
+ Subscribers::ActionControllerSubscriber.new
22
+ end
23
+
24
+ initializer 'rails_live_dashboard.action_record' do
25
+ Subscribers::ActiveRecordSubscriber.new
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,42 @@
1
+ module RailsLiveDashboard
2
+ module Recorders
3
+ class ExceptionRecorder
4
+ def initialize(exception)
5
+ @exception = exception
6
+ end
7
+
8
+ def execute
9
+ Exception.of_class(@exception.class).update_all(should_show: false)
10
+
11
+ Exception.create(
12
+ batch_id: RailsLiveDashboard::Context.instance.batch_id,
13
+ content: build_content
14
+ )
15
+ end
16
+
17
+ private
18
+
19
+ def build_content
20
+ occurrences = Exception.of_class(@exception.class).count
21
+
22
+ {
23
+ class: @exception.class,
24
+ message: @exception.message,
25
+ file: file_line[0],
26
+ line: file_line[1],
27
+ backtrace: @exception.backtrace,
28
+ occurrences: occurrences + 1
29
+ }
30
+ end
31
+
32
+ def file_line
33
+ return ['', ''] unless @exception.backtrace
34
+
35
+ file = @exception.backtrace[0].split(':').first
36
+ line = @exception.backtrace[0].split(':')[1]
37
+
38
+ [file, line]
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,30 @@
1
+ module RailsLiveDashboard
2
+ module Recorders
3
+ class QueryRecorder
4
+ def initialize(event)
5
+ @event = event
6
+ end
7
+
8
+ def execute
9
+ Query.create(
10
+ batch_id: RailsLiveDashboard::Context.instance.batch_id,
11
+ content: build_content
12
+ )
13
+ end
14
+
15
+ private
16
+
17
+ def build_content
18
+ payload = @event.payload
19
+ {
20
+ name: payload[:name],
21
+ sql: payload[:sql].strip.gsub(/(^(\s+)?$\n)/, ''),
22
+ parameters: payload[:type_casted_binds],
23
+ duration: (@event.end - @event.time).round(2),
24
+ kind: payload[:sql].match(/INSERT|UPDATE|DELETE/) ? 'WRITE' : 'READ',
25
+ cached: payload[:cached] ? true : false
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ module RailsLiveDashboard
2
+ module Recorders
3
+ class RequestRecorder
4
+ def initialize(event)
5
+ @event = event
6
+ end
7
+
8
+ def execute
9
+ Request.create(
10
+ batch_id: RailsLiveDashboard::Context.instance.batch_id,
11
+ content: build_content
12
+ )
13
+ end
14
+
15
+ private
16
+
17
+ def build_content
18
+ payload = @event.payload
19
+ payload.merge(
20
+ {
21
+ headers: payload[:request].headers.env.reject { |key| key.to_s.include?('.') },
22
+ body: payload[:response]&.body || nil,
23
+ duration: @event.duration.round(2),
24
+ allocations: @event.allocations
25
+ }
26
+ )
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,28 @@
1
+ module RailsLiveDashboard
2
+ module Subscribers
3
+ class ActionControllerSubscriber
4
+ def initialize
5
+ ActiveSupport::Notifications.subscribe 'start_processing.action_controller' do |_event|
6
+ RailsLiveDashboard::Context.instance.start
7
+ end
8
+
9
+ ActiveSupport::Notifications.subscribe 'process_action.action_controller' do |event|
10
+ next if event.payload[:controller].include?('RailsLiveDashboard')
11
+
12
+ handle_event(event)
13
+ rescue StandardError => e
14
+ Rails.logger.error "Error on handle action controller event: #{e.message}"
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def handle_event(event)
21
+ Recorders::RequestRecorder.new(event).execute
22
+ Recorders::ExceptionRecorder.new(event.payload[:exception_object]).execute if event.payload[:exception_object]
23
+
24
+ RailsLiveDashboard::Context.instance.reset
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ module RailsLiveDashboard
2
+ module Subscribers
3
+ class ActiveRecordSubscriber
4
+ def initialize
5
+ ActiveSupport::Notifications.subscribe 'sql.active_record' do |event|
6
+ next if should_skip(event)
7
+
8
+ Recorders::QueryRecorder.new(event).execute
9
+ rescue StandardError => e
10
+ Rails.logger.error "ActionRecordSubscriber - Error on handle active record event: #{e.message}"
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def should_skip(event)
17
+ event.payload[:name].blank? ||
18
+ event.payload[:name].match(/SCHEMA|TRANSACTION|ActiveRecord|RailsLiveDashboard/) ||
19
+ event.payload[:sql].match(/BEGIN|COMMIT/)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ module RailsLiveDashboard
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,19 @@
1
+ require 'rails_live_dashboard/version'
2
+ require 'rails_live_dashboard/engine'
3
+ require 'rails_live_dashboard/configuration'
4
+ require 'rails_live_dashboard/context'
5
+ require 'rails_live_dashboard/recorders/exception_recorder'
6
+ require 'rails_live_dashboard/recorders/request_recorder'
7
+ require 'rails_live_dashboard/recorders/query_recorder'
8
+ require 'rails_live_dashboard/subscribers/action_controller_subscriber'
9
+ require 'rails_live_dashboard/subscribers/active_record_subscriber'
10
+
11
+ module RailsLiveDashboard
12
+ def self.configuration
13
+ @configuration ||= Configuration.instance
14
+ end
15
+
16
+ def self.configure
17
+ yield(configuration)
18
+ end
19
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :rails_live_dashboard do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_live_dashboard
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Anderson Dalmina
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-02-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 7.1.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 7.1.3
27
+ description: Realtime dashboard for Rails applications
28
+ email:
29
+ - andersondalmina@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - MIT-LICENSE
35
+ - README.md
36
+ - Rakefile
37
+ - app/assets/builds/rails_live_dashboard/application.css
38
+ - app/assets/builds/rails_live_dashboard/application.js
39
+ - app/assets/builds/rails_live_dashboard/application.js.map
40
+ - app/assets/javascripts/rails_live_dashboard/application.js
41
+ - app/assets/javascripts/rails_live_dashboard/controllers/application.js
42
+ - app/assets/javascripts/rails_live_dashboard/controllers/index.js
43
+ - app/assets/javascripts/rails_live_dashboard/controllers/reveal_controller.js
44
+ - app/assets/javascripts/rails_live_dashboard/controllers/tabs_controller.js
45
+ - app/assets/stylesheets/rails_live_dashboard/application.css
46
+ - app/components/rails_live_dashboard/query_duration_badge_component.html.erb
47
+ - app/components/rails_live_dashboard/query_duration_badge_component.rb
48
+ - app/components/rails_live_dashboard/request_duration_badge_component.html.erb
49
+ - app/components/rails_live_dashboard/request_duration_badge_component.rb
50
+ - app/components/rails_live_dashboard/request_method_badge_component.html.erb
51
+ - app/components/rails_live_dashboard/request_method_badge_component.rb
52
+ - app/components/rails_live_dashboard/request_status_badge_component.html.erb
53
+ - app/components/rails_live_dashboard/request_status_badge_component.rb
54
+ - app/controllers/rails_live_dashboard/application_controller.rb
55
+ - app/controllers/rails_live_dashboard/clean_controller.rb
56
+ - app/controllers/rails_live_dashboard/dashboard_controller.rb
57
+ - app/controllers/rails_live_dashboard/exceptions_controller.rb
58
+ - app/controllers/rails_live_dashboard/queries_controller.rb
59
+ - app/controllers/rails_live_dashboard/requests_controller.rb
60
+ - app/controllers/rails_live_dashboard/widgets/slowest_queries_controller.rb
61
+ - app/controllers/rails_live_dashboard/widgets/slowest_requests_controller.rb
62
+ - app/helpers/rails_live_dashboard/application_helper.rb
63
+ - app/helpers/rails_live_dashboard/clean_helper.rb
64
+ - app/helpers/rails_live_dashboard/dashboard_helper.rb
65
+ - app/helpers/rails_live_dashboard/exceptions_helper.rb
66
+ - app/helpers/rails_live_dashboard/requests_helper.rb
67
+ - app/jobs/rails_live_dashboard/application_job.rb
68
+ - app/mailers/rails_live_dashboard/application_mailer.rb
69
+ - app/models/rails_live_dashboard/application_record.rb
70
+ - app/models/rails_live_dashboard/entry.rb
71
+ - app/models/rails_live_dashboard/exception.rb
72
+ - app/models/rails_live_dashboard/query.rb
73
+ - app/models/rails_live_dashboard/request.rb
74
+ - app/models/rails_live_dashboard/types/content.rb
75
+ - app/models/rails_live_dashboard/types/exception_content.rb
76
+ - app/models/rails_live_dashboard/types/query_content.rb
77
+ - app/models/rails_live_dashboard/types/request_content.rb
78
+ - app/views/layouts/rails_live_dashboard/application.html.erb
79
+ - app/views/rails_live_dashboard/dashboard/show.html.erb
80
+ - app/views/rails_live_dashboard/exceptions/_tabs.html.erb
81
+ - app/views/rails_live_dashboard/exceptions/index.html.erb
82
+ - app/views/rails_live_dashboard/exceptions/show.html.erb
83
+ - app/views/rails_live_dashboard/queries/_list.html.erb
84
+ - app/views/rails_live_dashboard/queries/index.html.erb
85
+ - app/views/rails_live_dashboard/queries/show.html.erb
86
+ - app/views/rails_live_dashboard/requests/_contents.html.erb
87
+ - app/views/rails_live_dashboard/requests/_exceptions.html.erb
88
+ - app/views/rails_live_dashboard/requests/_queries.html.erb
89
+ - app/views/rails_live_dashboard/requests/_relateds.html.erb
90
+ - app/views/rails_live_dashboard/requests/index.html.erb
91
+ - app/views/rails_live_dashboard/requests/show.html.erb
92
+ - app/views/rails_live_dashboard/shared/_header.html.erb
93
+ - app/views/rails_live_dashboard/widgets/slowest_queries/show.html.erb
94
+ - app/views/rails_live_dashboard/widgets/slowest_requests/show.html.erb
95
+ - config/routes.rb
96
+ - db/migrate/20240213133517_create_rails_live_dashboard_entries.rb
97
+ - lib/generators/rails_live_dashboard/install_generator.rb
98
+ - lib/generators/templates/initializer.rb
99
+ - lib/rails_live_dashboard.rb
100
+ - lib/rails_live_dashboard/configuration.rb
101
+ - lib/rails_live_dashboard/context.rb
102
+ - lib/rails_live_dashboard/engine.rb
103
+ - lib/rails_live_dashboard/recorders/exception_recorder.rb
104
+ - lib/rails_live_dashboard/recorders/query_recorder.rb
105
+ - lib/rails_live_dashboard/recorders/request_recorder.rb
106
+ - lib/rails_live_dashboard/subscribers/action_controller_subscriber.rb
107
+ - lib/rails_live_dashboard/subscribers/active_record_subscriber.rb
108
+ - lib/rails_live_dashboard/version.rb
109
+ - lib/tasks/rails_live_dashboard_tasks.rake
110
+ homepage: https://github.com/andersondalmina/rails-live-dashboard
111
+ licenses:
112
+ - MIT
113
+ metadata:
114
+ homepage_uri: https://github.com/andersondalmina/rails-live-dashboard
115
+ source_code_uri: https://github.com/andersondalmina/rails-live-dashboard
116
+ changelog_uri: https://github.com/andersondalmina/rails-live-dashboard/blob/main/CHANGELOG.md
117
+ post_install_message:
118
+ rdoc_options: []
119
+ require_paths:
120
+ - lib
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ requirements: []
132
+ rubygems_version: 3.4.10
133
+ signing_key:
134
+ specification_version: 4
135
+ summary: Realtime dashboard for Rails applications
136
+ test_files: []