rails_mini_profiler 0.1.0

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 (79) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +220 -0
  3. data/Rakefile +18 -0
  4. data/app/assets/config/rails_mini_profiler_manifest.js +1 -0
  5. data/app/assets/images/rails_mini_profiler/bookmark.svg +10 -0
  6. data/app/assets/images/rails_mini_profiler/chart.svg +12 -0
  7. data/app/assets/images/rails_mini_profiler/delete.svg +9 -0
  8. data/app/assets/images/rails_mini_profiler/graph.svg +11 -0
  9. data/app/assets/images/rails_mini_profiler/logo.svg +18 -0
  10. data/app/assets/images/rails_mini_profiler/logo_variant.svg +32 -0
  11. data/app/assets/images/rails_mini_profiler/search.svg +10 -0
  12. data/app/assets/images/rails_mini_profiler/setting.svg +10 -0
  13. data/app/assets/images/rails_mini_profiler/show.svg +11 -0
  14. data/app/assets/javascripts/rails_mini_profiler.js +90 -0
  15. data/app/assets/stylesheets/rails_mini_profiler/application.css +164 -0
  16. data/app/assets/stylesheets/rails_mini_profiler/flamegraph.css +14 -0
  17. data/app/assets/stylesheets/rails_mini_profiler/flashes.css +17 -0
  18. data/app/assets/stylesheets/rails_mini_profiler/navbar.css +50 -0
  19. data/app/assets/stylesheets/rails_mini_profiler/profiled_requests.css +180 -0
  20. data/app/assets/stylesheets/rails_mini_profiler/traces.css +87 -0
  21. data/app/controllers/rails_mini_profiler/application_controller.rb +28 -0
  22. data/app/controllers/rails_mini_profiler/flamegraphs_controller.rb +23 -0
  23. data/app/controllers/rails_mini_profiler/profiled_requests_controller.rb +55 -0
  24. data/app/helpers/rails_mini_profiler/application_helper.rb +12 -0
  25. data/app/helpers/rails_mini_profiler/profiled_requests_helper.rb +16 -0
  26. data/app/models/rails_mini_profiler/application_record.rb +17 -0
  27. data/app/models/rails_mini_profiler/controller_trace.rb +33 -0
  28. data/app/models/rails_mini_profiler/flamegraph.rb +33 -0
  29. data/app/models/rails_mini_profiler/instantiation_trace.rb +33 -0
  30. data/app/models/rails_mini_profiler/profiled_request.rb +59 -0
  31. data/app/models/rails_mini_profiler/render_partial_trace.rb +33 -0
  32. data/app/models/rails_mini_profiler/render_template_trace.rb +33 -0
  33. data/app/models/rails_mini_profiler/rmp_trace.rb +31 -0
  34. data/app/models/rails_mini_profiler/sequel_trace.rb +33 -0
  35. data/app/models/rails_mini_profiler/trace.rb +42 -0
  36. data/app/presenters/rails_mini_profiler/base_presenter.rb +25 -0
  37. data/app/presenters/rails_mini_profiler/controller_trace_presenter.rb +18 -0
  38. data/app/presenters/rails_mini_profiler/instantiation_trace_presenter.rb +14 -0
  39. data/app/presenters/rails_mini_profiler/profiled_request_presenter.rb +45 -0
  40. data/app/presenters/rails_mini_profiler/render_partial_trace_presenter.rb +11 -0
  41. data/app/presenters/rails_mini_profiler/render_template_trace_presenter.rb +15 -0
  42. data/app/presenters/rails_mini_profiler/rmp_trace_presenter.rb +9 -0
  43. data/app/presenters/rails_mini_profiler/sequel_trace_presenter.rb +69 -0
  44. data/app/presenters/rails_mini_profiler/trace_presenter.rb +61 -0
  45. data/app/views/layouts/rails_mini_profiler/application.html.erb +26 -0
  46. data/app/views/layouts/rails_mini_profiler/flamegraph.html.erb +18 -0
  47. data/app/views/rails_mini_profiler/badge.html.erb +37 -0
  48. data/app/views/rails_mini_profiler/flamegraphs/show.html.erb +13 -0
  49. data/app/views/rails_mini_profiler/profiled_requests/index.html.erb +59 -0
  50. data/app/views/rails_mini_profiler/profiled_requests/shared/_trace.html.erb +40 -0
  51. data/app/views/rails_mini_profiler/profiled_requests/show.html.erb +40 -0
  52. data/app/views/rails_mini_profiler/shared/_flashes.html.erb +8 -0
  53. data/app/views/rails_mini_profiler/shared/_navbar.html.erb +15 -0
  54. data/config/routes.rb +11 -0
  55. data/db/migrate/20210621185018_create_rmp.rb +44 -0
  56. data/lib/generators/rails_mini_profiler/USAGE +2 -0
  57. data/lib/generators/rails_mini_profiler/install_generator.rb +16 -0
  58. data/lib/generators/rails_mini_profiler/templates/rails_mini_profiler.rb.erb +13 -0
  59. data/lib/rails_mini_profiler.rb +55 -0
  60. data/lib/rails_mini_profiler/badge.rb +62 -0
  61. data/lib/rails_mini_profiler/configuration.rb +41 -0
  62. data/lib/rails_mini_profiler/engine.rb +23 -0
  63. data/lib/rails_mini_profiler/errors.rb +8 -0
  64. data/lib/rails_mini_profiler/flamegraph_guard.rb +47 -0
  65. data/lib/rails_mini_profiler/guard.rb +46 -0
  66. data/lib/rails_mini_profiler/logger.rb +20 -0
  67. data/lib/rails_mini_profiler/middleware.rb +74 -0
  68. data/lib/rails_mini_profiler/models/base_model.rb +18 -0
  69. data/lib/rails_mini_profiler/models/trace.rb +9 -0
  70. data/lib/rails_mini_profiler/redirect.rb +25 -0
  71. data/lib/rails_mini_profiler/request_context.rb +62 -0
  72. data/lib/rails_mini_profiler/request_wrapper.rb +33 -0
  73. data/lib/rails_mini_profiler/response_wrapper.rb +32 -0
  74. data/lib/rails_mini_profiler/storage.rb +29 -0
  75. data/lib/rails_mini_profiler/tracers.rb +85 -0
  76. data/lib/rails_mini_profiler/user.rb +40 -0
  77. data/lib/rails_mini_profiler/version.rb +5 -0
  78. data/lib/tasks/rails_mini_profiler_tasks.rake +8 -0
  79. metadata +151 -0
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsMiniProfiler
4
+ class ApplicationController < ::ApplicationController
5
+ rescue_from ActiveRecord::RecordNotFound, with: :not_found
6
+
7
+ before_action :check_current_user
8
+
9
+ protected
10
+
11
+ def present(model, presenter_class = nil, **kwargs)
12
+ klass = presenter_class || "RailsMiniProfiler::#{model.class.to_s.demodulize}Presenter".constantize
13
+ presenter = klass.new(model, view_context, **kwargs)
14
+ yield(presenter) if block_given?
15
+ presenter
16
+ end
17
+
18
+ private
19
+
20
+ def not_found(error)
21
+ redirect_back(fallback_location: profiled_requests_path, alert: error.to_s)
22
+ end
23
+
24
+ def check_current_user
25
+ redirect_back(fallback_location: root_path) unless User.get(request.env).present?
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency 'rails_mini_profiler/application_controller'
4
+
5
+ module RailsMiniProfiler
6
+ class FlamegraphsController < ApplicationController
7
+ layout 'rails_mini_profiler/flamegraph'
8
+
9
+ before_action :set_flamegraph, only: %i[show]
10
+
11
+ def show; end
12
+
13
+ private
14
+
15
+ def set_flamegraph
16
+ @flamegraph = Flamegraph.find_by!(rmp_profiled_request_id: params[:id]).json_data
17
+ end
18
+
19
+ def configuration
20
+ @configuration ||= RailsMiniProfiler.configuration
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency 'rails_mini_profiler/application_controller'
4
+
5
+ module RailsMiniProfiler
6
+ class ProfiledRequestsController < ApplicationController
7
+ before_action :set_profiled_request, only: %i[show destroy]
8
+
9
+ def index
10
+ @profiled_requests = ProfiledRequest
11
+ .includes(:flamegraph)
12
+ .where(user_id: user_id).order(id: :desc)
13
+ @profiled_requests = @profiled_requests.where('request_path LIKE ?', "%#{params[:path]}%") if params[:path]
14
+ @profiled_requests = @profiled_requests.map { |request| present(request) }
15
+ end
16
+
17
+ def show
18
+ @traces = @profiled_request.traces
19
+ @traces = @traces.where('payload LIKE ?', "%#{params[:search]}%") if params[:search]
20
+ @traces = @traces
21
+ .order(:start)
22
+ .map { |trace| present(trace, profiled_request: @profiled_request) }
23
+ @profiled_request = present(@profiled_request)
24
+ end
25
+
26
+ def destroy
27
+ ProfiledRequest.where(user_id: user_id).destroy(@profiled_request.id)
28
+ redirect_to profiled_requests_url, notice: 'Profiled request was successfully destroyed.'
29
+ end
30
+
31
+ def destroy_all
32
+ ProfiledRequest.transaction do
33
+ requests_table_name = RailsMiniProfiler.storage_configuration.profiled_requests_table.to_sym
34
+ Flamegraph.joins(:profiled_request).where(requests_table_name => { user_id: user_id }).delete_all
35
+ Trace.joins(:profiled_request).where(requests_table_name => { user_id: user_id }).delete_all
36
+ ProfiledRequest.where(requests_table_name => { user_id: user_id }).delete_all
37
+ end
38
+ redirect_to profiled_requests_url, notice: 'Profiled Requests cleared'
39
+ end
40
+
41
+ private
42
+
43
+ def user_id
44
+ @user_id ||= User.get(request.env)
45
+ end
46
+
47
+ def set_profiled_request
48
+ @profiled_request = ProfiledRequest.where(user_id: user_id).find(params[:id])
49
+ end
50
+
51
+ def configuration
52
+ @configuration ||= RailsMiniProfiler.configuration
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsMiniProfiler
4
+ module ApplicationHelper
5
+ def present(model, presenter_class = nil, **kwargs)
6
+ klass = presenter_class || "#{model.class}Presenter".constantize
7
+ presenter = klass.new(model, self, **kwargs)
8
+ yield(presenter) if block_given?
9
+ presenter
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsMiniProfiler
4
+ module ProfiledRequestsHelper
5
+ include ApplicationHelper
6
+
7
+ def formatted_duration(duration)
8
+ duration = (duration.to_f / 100)
9
+ duration < 1 ? duration : duration.round
10
+ end
11
+
12
+ def formatted_allocations(allocations)
13
+ number_to_human(allocations, units: { unit: '', thousand: 'k', million: 'M', billion: 'B', trillion: 'T' })
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsMiniProfiler
4
+ class ApplicationRecord < ActiveRecord::Base
5
+ if RailsMiniProfiler.storage_configuration.database.present?
6
+ establish_connection(RailsMiniProfiler.storage_configuration.database.present?)
7
+ end
8
+
9
+ self.abstract_class = true
10
+
11
+ def self.record_timestamps
12
+ # Some applications may disable timestamp setting, but in the context of the engine we always want to record
13
+ # timestamps, as engine functionality relies on it.
14
+ true
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # == Schema Information
4
+ #
5
+ # Table name: rmp_traces
6
+ #
7
+ # id :integer not null, primary key
8
+ # rmp_profiled_request_id :bigint not null
9
+ # name :string
10
+ # start :integer
11
+ # finish :integer
12
+ # duration :integer
13
+ # allocations :integer
14
+ # payload :json
15
+ # backtrace :json
16
+ # created_at :datetime not null
17
+ # updated_at :datetime not null
18
+ #
19
+ module RailsMiniProfiler
20
+ class ControllerTrace < Trace
21
+ store :payload, accessors: %i[view_runtime db_runtime]
22
+
23
+ class << self
24
+ def find_sti_class(_)
25
+ super(name)
26
+ end
27
+
28
+ def sti_name
29
+ 'process_action.action_controller'
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # == Schema Information
4
+ #
5
+ # Table name: rmp_flamegraphs
6
+ #
7
+ # id :integer not null, primary key
8
+ # rmp_profiled_request_id :bigint not null
9
+ # data :binary
10
+ # created_at :datetime not null
11
+ # updated_at :datetime not null
12
+ #
13
+ module RailsMiniProfiler
14
+ class Flamegraph < RailsMiniProfiler::ApplicationRecord
15
+ self.table_name = RailsMiniProfiler.storage_configuration.flamegraphs_table
16
+
17
+ belongs_to :profiled_request,
18
+ class_name: 'RailsMiniProfiler::ProfiledRequest',
19
+ foreign_key: :rmp_profiled_request_id
20
+
21
+ before_save :compress
22
+
23
+ def json_data
24
+ @json_data = ActiveSupport::Gzip.decompress(data)
25
+ end
26
+
27
+ private
28
+
29
+ def compress
30
+ self.data = ActiveSupport::Gzip.compress(data)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # == Schema Information
4
+ #
5
+ # Table name: rmp_traces
6
+ #
7
+ # id :integer not null, primary key
8
+ # rmp_profiled_request_id :bigint not null
9
+ # name :string
10
+ # start :integer
11
+ # finish :integer
12
+ # duration :integer
13
+ # allocations :integer
14
+ # payload :json
15
+ # backtrace :json
16
+ # created_at :datetime not null
17
+ # updated_at :datetime not null
18
+ #
19
+ module RailsMiniProfiler
20
+ class InstantiationTrace < Trace
21
+ store :payload, accessors: %i[record_count class_name]
22
+
23
+ class << self
24
+ def find_sti_class(_)
25
+ super(name)
26
+ end
27
+
28
+ def sti_name
29
+ 'instantiation.active_record'
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ # == Schema Information
4
+ #
5
+ # Table name: rmp_profiled_requests
6
+ #
7
+ # id :integer not null, primary key
8
+ # user_id :string
9
+ # start :integer
10
+ # finish :integer
11
+ # duration :integer
12
+ # allocations :integer
13
+ # request_path :string
14
+ # request_method :string
15
+ # request_headers :json
16
+ # request_body :json
17
+ # response_status :integer
18
+ # response_body :json
19
+ # response_headers :json
20
+ # created_at :datetime not null
21
+ # updated_at :datetime not null
22
+ #
23
+ module RailsMiniProfiler
24
+ class ProfiledRequest < RailsMiniProfiler::ApplicationRecord
25
+ self.table_name = RailsMiniProfiler.storage_configuration.profiled_requests_table
26
+
27
+ has_one :flamegraph,
28
+ class_name: 'RailsMiniProfiler::Flamegraph',
29
+ foreign_key: :rmp_profiled_request_id,
30
+ dependent: :destroy
31
+
32
+ has_many :traces,
33
+ class_name: 'RailsMiniProfiler::Trace',
34
+ foreign_key: :rmp_profiled_request_id,
35
+ dependent: :destroy
36
+
37
+ def request=(request)
38
+ self.request_body = request.body
39
+ self.request_headers = request.headers
40
+ self.request_method = request.method
41
+ self.request_path = request.path
42
+ self.request_query_string = request.query_string
43
+ end
44
+
45
+ def response=(response)
46
+ self.response_body = response.body
47
+ self.response_media_type = response.media_type
48
+ self.response_headers = response.headers
49
+ self.response_status = response.status
50
+ end
51
+
52
+ def total_time=(total_time)
53
+ self.start = total_time.start
54
+ self.finish = total_time.finish
55
+ self.duration = total_time.duration
56
+ self.allocations = total_time.allocations
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # == Schema Information
4
+ #
5
+ # Table name: rmp_traces
6
+ #
7
+ # id :integer not null, primary key
8
+ # rmp_profiled_request_id :bigint not null
9
+ # name :string
10
+ # start :integer
11
+ # finish :integer
12
+ # duration :integer
13
+ # allocations :integer
14
+ # payload :json
15
+ # backtrace :json
16
+ # created_at :datetime not null
17
+ # updated_at :datetime not null
18
+ #
19
+ module RailsMiniProfiler
20
+ class RenderPartialTrace < Trace
21
+ store :payload, accessors: %i[identifier]
22
+
23
+ class << self
24
+ def find_sti_class(_)
25
+ super(name)
26
+ end
27
+
28
+ def sti_name
29
+ 'render_partial.action_view'
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # == Schema Information
4
+ #
5
+ # Table name: rmp_traces
6
+ #
7
+ # id :integer not null, primary key
8
+ # rmp_profiled_request_id :bigint not null
9
+ # name :string
10
+ # start :integer
11
+ # finish :integer
12
+ # duration :integer
13
+ # allocations :integer
14
+ # payload :json
15
+ # backtrace :json
16
+ # created_at :datetime not null
17
+ # updated_at :datetime not null
18
+ #
19
+ module RailsMiniProfiler
20
+ class RenderTemplateTrace < Trace
21
+ store :payload, accessors: %i[identifier]
22
+
23
+ class << self
24
+ def find_sti_class(_)
25
+ super(name)
26
+ end
27
+
28
+ def sti_name
29
+ 'render_template.action_view'
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # == Schema Information
4
+ #
5
+ # Table name: rmp_traces
6
+ #
7
+ # id :integer not null, primary key
8
+ # rmp_profiled_request_id :bigint not null
9
+ # name :string
10
+ # start :integer
11
+ # finish :integer
12
+ # duration :integer
13
+ # allocations :integer
14
+ # payload :json
15
+ # backtrace :json
16
+ # created_at :datetime not null
17
+ # updated_at :datetime not null
18
+ #
19
+ module RailsMiniProfiler
20
+ class RmpTrace < Trace
21
+ class << self
22
+ def find_sti_class(_)
23
+ super(name)
24
+ end
25
+
26
+ def sti_name
27
+ 'rails_mini_profiler.total_time'
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # == Schema Information
4
+ #
5
+ # Table name: rmp_traces
6
+ #
7
+ # id :integer not null, primary key
8
+ # rmp_profiled_request_id :bigint not null
9
+ # name :string
10
+ # start :integer
11
+ # finish :integer
12
+ # duration :integer
13
+ # allocations :integer
14
+ # payload :json
15
+ # backtrace :json
16
+ # created_at :datetime not null
17
+ # updated_at :datetime not null
18
+ #
19
+ module RailsMiniProfiler
20
+ class SequelTrace < Trace
21
+ store :payload, accessors: %i[name sql binds]
22
+
23
+ class << self
24
+ def find_sti_class(_)
25
+ super(name)
26
+ end
27
+
28
+ def sti_name
29
+ 'sql.active_record'
30
+ end
31
+ end
32
+ end
33
+ end