dial 0.1.2 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c1ac4b6e83d9c20da87125b635bb0d9e98d71147d1fa0490606bc7f5431aa171
4
- data.tar.gz: ad2c423d69ade789af8cb6c52776d1688607a6a97c04215c231f26931a986f0d
3
+ metadata.gz: 61252b82f8769e8c0724a9cb40a8771afc59df61de01847add599037939b1e7d
4
+ data.tar.gz: 3944fe8e444853a4dfe4f2fb474bf6ed6a4b30814d55dc127df986e99c08bcf6
5
5
  SHA512:
6
- metadata.gz: 957163d6a4b723704c6956d0056f6f36a67f1ce07415b5e39ae84be396ca58a77cb5fd076ce8dec8471e019e10d7fb516594cb8c9ea5806b7c80f15af8063c17
7
- data.tar.gz: df6125c631c2948aa24cc03508f951b47bc198c39ecc34d4a1a091eb265c0b6aa572f75d8e6b4883d6856b2bf830ba1bd7617e6e0fb5bacd924c7475876302fd
6
+ metadata.gz: cdbc7c51f7392b280a56f56d232204c93ee77e436ee6891f7f88e9d9c39570b77b85af3ff07dc15a54c854757053be0ab8c85d7adb6c21ed23f438c43c0d4da7
7
+ data.tar.gz: 8b8b5400414355f6012d87b490b719ab3b79cfacc229705e752e8822162cc383979e8898711f76b0b1393c497ec0c5a0cd4a344f9050ab1832e1317b314c30bd
data/CHANGELOG.md CHANGED
@@ -1,13 +1,18 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.1.4] - 2024-12-27
4
+
5
+ - Use vernier memory usage and rails hooks by default
6
+ - Add support for N+1 detection with prosopite
7
+
8
+ ## [0.1.3] - 2024-11-14
9
+
10
+ - Enable allocation profiling by default
11
+
3
12
  ## [0.1.2] - 2024-11-10
4
13
 
5
14
  - Add support for request profiling with vernier
6
15
 
7
16
  ## [0.1.1] - 2024-11-08
8
17
 
9
- - Set upper bound on dependencies
10
-
11
- ## [0.1.0] - 2024-11-08
12
-
13
18
  - Initial release
data/README.md CHANGED
@@ -7,26 +7,24 @@ WIP
7
7
 
8
8
  A modern profiler for Rails applications.
9
9
 
10
- <details>
11
- <summary>POC</summary>
12
-
13
- ![Snapshot 1](https://github.com/user-attachments/assets/904daaf5-3f18-4c94-a7e4-9418539a19f3)
14
-
15
- ![Snapshot 2](https://github.com/user-attachments/assets/eb6ed9f5-b258-42df-8901-222c7d969fdd)
16
-
17
- https://github.com/user-attachments/assets/bae59681-ebeb-42b3-9489-9692c072c3dc
18
-
19
- </details>
10
+ Check out the demo:
11
+ [![Demo](https://img.youtube.com/vi/LPXtfJ0c284/maxresdefault.jpg)](https://youtu.be/LPXtfJ0c284)
20
12
 
21
13
  ## Installation
22
14
 
23
- Install the gem and add it to your Rails application's Gemfile by executing:
15
+ 1. Install the gem and add it to your Rails application's Gemfile by executing:
24
16
 
25
17
  ```bash
26
18
  bundle add dial
27
19
  ```
28
20
 
29
- and everything should just work.
21
+ 2. Mount the engine in your `config/routes.rb` file:
22
+
23
+
24
+ ```ruby
25
+ # this will mount the engine at /dial
26
+ mount Dial::Engine, at: "/"
27
+ ```
30
28
 
31
29
  ## Development
32
30
 
data/dial.gemspec CHANGED
@@ -22,5 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.add_dependency "railties", ">= 7", "< 8.2"
23
23
  spec.add_dependency "activerecord", ">= 7", "< 8.2"
24
24
  spec.add_dependency "actionpack", ">= 7", "< 8.2"
25
- spec.add_dependency "vernier", "~> 1.3"
25
+ spec.add_dependency "vernier", "~> 1.5"
26
+ spec.add_dependency "prosopite", "~> 1.4"
27
+ spec.add_dependency "pg_query", "~> 5.1"
26
28
  end
@@ -1,6 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "version"
4
+
3
5
  module Dial
4
6
  REQUEST_TIMING_HEADER = "dial_request_timing"
7
+
8
+ PROFILE_OUT_STALE_SECONDS = 60 * 60
5
9
  PROFILE_OUT_RELATIVE_DIRNAME = "tmp/dial/profile/"
10
+
11
+ PROSOPITE_IGNORE_QUERIES = [/schema_migrations/]
12
+ PROSOPITE_LOG_RELATIVE_PATHNAME = "log/dial/prosopite.log"
6
13
  end
@@ -3,7 +3,7 @@
3
3
  Dial::Engine.routes.draw do
4
4
  scope path: "/dial", as: "dial" do
5
5
  get "profile", to: lambda { |env|
6
- uuid = env[Rack::QUERY_STRING].sub("uuid=", "")
6
+ uuid = env[::Rack::QUERY_STRING].sub "uuid=", ""
7
7
  path = String ::Rails.root.join Dial::PROFILE_OUT_RELATIVE_DIRNAME, "#{uuid}.json"
8
8
 
9
9
  if File.exist? path
@@ -1,22 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "cgi"
4
-
5
- require_relative "constants"
3
+ require "uri"
6
4
 
7
5
  module Dial
8
6
  class Panel
9
7
  class << self
10
- def html env, profile_out_filename, ruby_vm_stat, gc_stat, gc_stat_heap, server_timing
8
+ def html env, profile_out_filename, query_logs, ruby_vm_stat, gc_stat, gc_stat_heap, server_timing
11
9
  <<~HTML
12
10
  <style>#{style}</style>
13
11
 
14
12
  <div id="dial">
15
13
  <div id="dial-preview">
16
14
  <span>
17
- #{formatted_rails_route_info(env)} |
18
- #{formatted_request_timing(env)} |
19
- #{formatted_profile_ouput(env, profile_out_filename)}
15
+ #{formatted_rails_route_info env} |
16
+ #{formatted_request_timing env} |
17
+ #{formatted_profile_output env, profile_out_filename}
20
18
  </span>
21
19
  <span>#{formatted_rails_version}</span>
22
20
  <span>#{formatted_rack_version}</span>
@@ -27,30 +25,37 @@ module Dial
27
25
  <hr>
28
26
 
29
27
  <details>
30
- <summary>RubyVM stat</summary>
28
+ <summary>Server timing</summary>
31
29
  <div class="section">
32
- #{formatted_ruby_vm_stat(ruby_vm_stat)}
30
+ #{formatted_server_timing server_timing}
33
31
  </div>
34
32
  </details>
35
33
 
36
34
  <details>
37
- <summary>GC stat</summary>
35
+ <summary>N+1s</summary>
36
+ <div class="section query-logs">
37
+ #{formatted_query_logs query_logs}
38
+ </div>
39
+ </details>
40
+
41
+ <details>
42
+ <summary>RubyVM stat</summary>
38
43
  <div class="section">
39
- #{formatted_gc_stat(gc_stat)}
44
+ #{formatted_ruby_vm_stat ruby_vm_stat}
40
45
  </div>
41
46
  </details>
42
47
 
43
48
  <details>
44
- <summary>GC stat heap</summary>
49
+ <summary>GC stat</summary>
45
50
  <div class="section">
46
- #{formatted_gc_stat_heap(gc_stat_heap)}
51
+ #{formatted_gc_stat gc_stat}
47
52
  </div>
48
53
  </details>
49
54
 
50
55
  <details>
51
- <summary>Server timing</summary>
56
+ <summary>GC stat heap</summary>
52
57
  <div class="section">
53
- #{formatted_server_timing(server_timing)}
58
+ #{formatted_gc_stat_heap gc_stat_heap}
54
59
  </div>
55
60
  </details>
56
61
  </div>
@@ -77,42 +82,49 @@ module Dial
77
82
  padding: 0.5rem;
78
83
  font-size: 0.85rem;
79
84
  color: black;
80
- cursor: pointer;
81
- }
82
-
83
- #dial-preview {
84
- display: flex;
85
- flex-direction: column;
86
- cursor: pointer;
87
- }
88
-
89
- #dial-details {
90
- display: none;
91
- }
92
-
93
- .section {
94
- display: flex;
95
- flex-direction: column;
96
- margin-top: 0.5rem;
97
- }
98
-
99
- span {
100
- text-align: left;
101
- }
102
-
103
- hr {
104
- width: -moz-available;
105
- margin-top: 0.5rem;
106
- }
107
-
108
- details {
109
- margin-top: 0.5rem;
110
- text-align: left;
111
- }
112
85
 
113
- summary {
114
- margin-bottom: 0.25rem;
115
- cursor: pointer;
86
+ #dial-preview {
87
+ display: flex;
88
+ flex-direction: column;
89
+ cursor: pointer;
90
+ }
91
+
92
+ #dial-details {
93
+ display: none;
94
+ }
95
+
96
+ .section {
97
+ display: flex;
98
+ flex-direction: column;
99
+ margin: 0.25rem 0 0 0;
100
+ }
101
+
102
+ .query-logs {
103
+ padding-left: 0.75rem;
104
+
105
+ details {
106
+ margin-top: 0;
107
+ }
108
+ }
109
+
110
+ span {
111
+ text-align: left;
112
+ }
113
+
114
+ hr {
115
+ width: -moz-available;
116
+ margin: 0.65rem 0 0 0;
117
+ }
118
+
119
+ details {
120
+ margin: 0.5rem 0 0 0;
121
+ text-align: left;
122
+ }
123
+
124
+ summary {
125
+ margin: 0.25rem 0 0 0;
126
+ cursor: pointer;
127
+ }
116
128
  }
117
129
  CSS
118
130
  end
@@ -142,15 +154,13 @@ module Dial
142
154
  "<b>Request timing:</b> #{env[REQUEST_TIMING_HEADER]}ms"
143
155
  end
144
156
 
145
- def formatted_profile_ouput env, profile_out_filename
146
- uuid = profile_out_filename.sub ".json", ""
147
- path = "dial/profile?uuid=#{uuid}"
148
- host = env[::Rack::HTTP_HOST]
149
- base_url = ::Rails.application.routes.url_helpers.dial_url host: host
150
- profile_out_url = CGI.escape base_url + path
151
- url = "https://vernier.prof/from-url/#{profile_out_url}"
157
+ def formatted_profile_output env, profile_out_filename
158
+ url_base = ::Rails.application.routes.url_helpers.dial_url host: env[::Rack::HTTP_HOST]
159
+ prefix = "/" unless url_base.end_with? "/"
160
+ uuid = profile_out_filename.delete_suffix ".json"
161
+ profile_out_url = URI.encode_www_form_component url_base + "#{prefix}dial/profile?uuid=#{uuid}"
152
162
 
153
- "<a href='#{url}' target='_blank'>View profile</a>"
163
+ "<a href='https://vernier.prof/from-url/#{profile_out_url}' target='_blank'>View profile</a>"
154
164
  end
155
165
 
156
166
  def formatted_rails_version
@@ -162,7 +172,32 @@ module Dial
162
172
  end
163
173
 
164
174
  def formatted_ruby_version
165
- "<b>Ruby version:</b> #{RUBY_DESCRIPTION}"
175
+ "<b>Ruby version:</b> #{::RUBY_DESCRIPTION}"
176
+ end
177
+
178
+ def formatted_server_timing server_timing
179
+ if server_timing.any?
180
+ server_timing
181
+ # TODO: Nested sorting
182
+ .sort_by { |_, timing| -timing }
183
+ .map { |event, timing| "<span><b>#{event}:</b> #{timing}</span>" }.join
184
+ else
185
+ "NA"
186
+ end
187
+ end
188
+
189
+ def formatted_query_logs query_logs
190
+ query_logs.map do |(queries, stack_lines)|
191
+ <<~HTML
192
+ <details>
193
+ <summary>#{queries.shift}</summary>
194
+ <div class="section query-logs">
195
+ #{queries.map { |query| "<span>#{query}</span>" }.join}
196
+ #{stack_lines.map { |stack_line| "<span>#{stack_line}</span>" }.join}
197
+ </div>
198
+ </details>
199
+ HTML
200
+ end.join
166
201
  end
167
202
 
168
203
  def formatted_ruby_vm_stat ruby_vm_stat
@@ -185,17 +220,6 @@ module Dial
185
220
  HTML
186
221
  end.join
187
222
  end
188
-
189
- def formatted_server_timing server_timing
190
- if server_timing.any?
191
- server_timing
192
- # TODO: Nested sorting
193
- .sort_by { |_, timing| -timing }
194
- .map { |event, timing| "<span><b>#{event}:</b> #{timing}</span>" }.join
195
- else
196
- "NA"
197
- end
198
- end
199
223
  end
200
224
  end
201
225
  end
@@ -5,8 +5,8 @@ module Dial
5
5
  private
6
6
 
7
7
  def server_timing headers
8
- timing = if (ActionDispatch.const_defined? :Constants) && (ActionDispatch::Constants.const_defined? :SERVER_TIMING)
9
- headers[ActionDispatch::Constants::SERVER_TIMING]
8
+ timing = if ::ActionDispatch.const_defined? "Constants::SERVER_TIMING"
9
+ headers[::ActionDispatch::Constants::SERVER_TIMING]
10
10
  else
11
11
  headers["Server-Timing"]
12
12
  end
@@ -5,11 +5,11 @@ module Dial
5
5
  private
6
6
 
7
7
  def ruby_vm_stat_diff before, after
8
- stat_diff before, after, except: [:next_shape_id]
8
+ stat_diff before, after, no_diff: [:next_shape_id]
9
9
  end
10
10
 
11
11
  def gc_stat_diff before, after
12
- stat_diff before, after, except: [
12
+ stat_diff before, after, no_diff: [
13
13
  :heap_allocatable_slots,
14
14
  :malloc_increase_bytes_limit,
15
15
  :remembered_wb_unprotected_objects_limit,
@@ -20,14 +20,14 @@ module Dial
20
20
 
21
21
  def gc_stat_heap_diff before, after
22
22
  after.each_with_object({}) do |(slot_index, slot_stat), diff|
23
- diff[slot_index] = stat_diff before[slot_index], slot_stat, except: [:slot_size]
23
+ diff[slot_index] = stat_diff before[slot_index], slot_stat, no_diff: [:slot_size]
24
24
  end
25
25
  end
26
26
 
27
- def stat_diff before, after, except: []
28
- after.except(*except).each_with_object({}) do |(key, value), diff|
27
+ def stat_diff before, after, no_diff: []
28
+ after.except(*no_diff).each_with_object({}) do |(key, value), diff|
29
29
  diff[key] = value - before[key]
30
- end
30
+ end.merge after.slice *no_diff
31
31
  end
32
32
  end
33
33
  end
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "securerandom"
4
+
3
5
  require "vernier"
6
+ require "prosopite"
4
7
 
5
- require_relative "ruby_stat"
6
- require_relative "rails_stat"
7
- require_relative "constants"
8
- require_relative "panel"
8
+ require_relative "middleware/panel"
9
+ require_relative "middleware/ruby_stat"
10
+ require_relative "middleware/rails_stat"
9
11
 
10
12
  module Dial
11
13
  class Middleware
@@ -17,40 +19,38 @@ module Dial
17
19
  end
18
20
 
19
21
  def call env
20
- start_time = ::Process.clock_gettime ::Process::CLOCK_MONOTONIC
21
-
22
- ruby_vm_stat_before = RubyVM.stat
23
- gc_stat_before = GC.stat
24
- gc_stat_heap_before = GC.stat_heap
22
+ start_time = Process.clock_gettime Process::CLOCK_MONOTONIC
25
23
 
26
- profile_out_dirname = String ::Rails.root.join PROFILE_OUT_RELATIVE_DIRNAME
27
- FileUtils.mkdir_p profile_out_dirname
28
- profile_out_filename = "#{SecureRandom.uuid}.json"
29
- profile_out_pathname = "#{profile_out_dirname}#{profile_out_filename}"
24
+ profile_out_filename = "#{SecureRandom.uuid_v7}.json"
25
+ profile_out_pathname = "#{profile_out_dir_pathname}#{profile_out_filename}"
30
26
 
31
27
  status, headers, rack_body = nil
32
- ::Vernier.profile out: profile_out_pathname do
33
- status, headers, rack_body = @app.call env
28
+ ruby_vm_stat, gc_stat, gc_stat_heap = nil
29
+ ::Prosopite.scan do
30
+ ::Vernier.profile out: profile_out_pathname, interval: 500, allocation_interval: 1000, hooks: [:memory_usage, :rails] do
31
+ ruby_vm_stat, gc_stat, gc_stat_heap = with_diffed_ruby_stats do
32
+ status, headers, rack_body = @app.call env
33
+ end
34
+ end
34
35
  end
36
+ server_timing = server_timing headers
35
37
 
36
38
  unless headers[::Rack::CONTENT_TYPE]&.include? "text/html"
37
39
  File.delete profile_out_pathname if File.exist? profile_out_pathname
38
40
  return [status, headers, rack_body]
39
41
  end
40
42
 
41
- finish_time = ::Process.clock_gettime ::Process::CLOCK_MONOTONIC
42
- env[REQUEST_TIMING_HEADER] = ((finish_time - start_time) * 1_000).round 2
43
+ query_logs = clear_query_logs!
44
+ remove_stale_profile_out_files!
43
45
 
44
- ruby_vm_stat_diff = ruby_vm_stat_diff ruby_vm_stat_before, RubyVM.stat
45
- gc_stat_diff = gc_stat_diff gc_stat_before, GC.stat
46
- gc_stat_heap_diff = gc_stat_heap_diff gc_stat_heap_before, GC.stat_heap
47
- server_timing = server_timing headers
46
+ finish_time = Process.clock_gettime Process::CLOCK_MONOTONIC
47
+ env[REQUEST_TIMING_HEADER] = ((finish_time - start_time) * 1_000).round 2
48
48
 
49
49
  body = String.new.tap do |str|
50
50
  rack_body.each { |chunk| str << chunk }
51
- rack_body.close if body.respond_to? :close
51
+ rack_body.close if rack_body.respond_to? :close
52
52
  end.sub "</body>", <<~HTML
53
- #{Panel.html env, profile_out_filename, ruby_vm_stat_diff, gc_stat_diff, gc_stat_heap_diff, server_timing}
53
+ #{Panel.html env, profile_out_filename, query_logs, ruby_vm_stat, gc_stat, gc_stat_heap, server_timing}
54
54
  </body>
55
55
  HTML
56
56
 
@@ -58,5 +58,77 @@ module Dial
58
58
 
59
59
  [status, headers, [body]]
60
60
  end
61
+
62
+ private
63
+
64
+ def with_diffed_ruby_stats
65
+ ruby_vm_stat_before = RubyVM.stat
66
+ gc_stat_before = GC.stat
67
+ gc_stat_heap_before = GC.stat_heap
68
+ yield
69
+ [
70
+ ruby_vm_stat_diff(ruby_vm_stat_before, RubyVM.stat),
71
+ gc_stat_diff(gc_stat_before, GC.stat),
72
+ gc_stat_heap_diff(gc_stat_heap_before, GC.stat_heap)
73
+ ]
74
+ end
75
+
76
+ def remove_stale_profile_out_files!
77
+ stale_profile_out_files.each do |profile_out_file|
78
+ File.delete profile_out_file
79
+ end
80
+ end
81
+
82
+ def stale_profile_out_files
83
+ Dir.glob("#{profile_out_dir_pathname}/*.json").select do |profile_out_file|
84
+ timestamp = Util.uuid_v7_timestamp File.basename profile_out_file
85
+ timestamp < Time.now - PROFILE_OUT_STALE_SECONDS
86
+ end
87
+ end
88
+
89
+ def profile_out_dir_pathname
90
+ @_profile_out_dir_pathname ||= ::Rails.root.join PROFILE_OUT_RELATIVE_DIRNAME
91
+ end
92
+
93
+ def clear_query_logs!
94
+ [].tap do |query_logs|
95
+ File.open(query_log_pathname, "r+") do |file|
96
+ entry = reading_section = query_count = nil
97
+ file.each_line do |line|
98
+ case line
99
+ when /N\+1 queries detected/
100
+ entry = [[], []]
101
+ reading_section = :queries
102
+ query_count = 0
103
+ when /Call stack/
104
+ reading_section = :call_stack
105
+ if query_count > 5
106
+ entry.first << "+ #{query_count - 5} more queries"
107
+ end
108
+ else
109
+ case reading_section
110
+ when :queries
111
+ query_count += 1
112
+ entry.first << line.strip if query_count <= 5
113
+ when :call_stack
114
+ if line.strip.empty?
115
+ query_logs << entry
116
+ reading_section = nil
117
+ else
118
+ entry.last << line.strip
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ file.truncate 0
125
+ file.rewind
126
+ end
127
+ end
128
+ end
129
+
130
+ def query_log_pathname
131
+ @_query_log_dir_pathname ||= ::Rails.root.join PROSOPITE_LOG_RELATIVE_PATHNAME
132
+ end
61
133
  end
62
134
  end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dial
4
+ class ProsopiteLogger < Logger
5
+ end
6
+ end
data/lib/dial/railtie.rb CHANGED
@@ -1,13 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rails"
4
+ require "prosopite"
4
5
 
5
6
  require_relative "middleware"
7
+ require_relative "prosopite_logger"
6
8
 
7
9
  module Dial
8
10
  class Railtie < ::Rails::Railtie
9
11
  initializer "dial.use_middleware" do |app|
10
12
  app.middleware.insert_before 0, Middleware
11
13
  end
14
+
15
+ initializer "dial.set_up_vernier" do |app|
16
+ app.config.after_initialize do
17
+ FileUtils.mkdir_p ::Rails.root.join PROFILE_OUT_RELATIVE_DIRNAME
18
+ end
19
+ end
20
+
21
+ initializer "dial.set_up_prosopite" do |app|
22
+ app.config.after_initialize do
23
+ if ::ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
24
+ require "pg_query"
25
+ end
26
+
27
+ prosopite_log_pathname = ::Rails.root.join PROSOPITE_LOG_RELATIVE_PATHNAME
28
+ FileUtils.mkdir_p File.dirname prosopite_log_pathname
29
+ FileUtils.touch prosopite_log_pathname
30
+ ::Prosopite.custom_logger = ProsopiteLogger.new prosopite_log_pathname
31
+
32
+ ::Prosopite.ignore_queries = PROSOPITE_IGNORE_QUERIES
33
+ end
34
+ end
12
35
  end
13
36
  end
data/lib/dial/util.rb ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dial
4
+ module Util
5
+ class << self
6
+ def uuid_v7_timestamp uuid
7
+ high_bits_hex = uuid.split("-").first(2).join[0, 12].to_i 16
8
+ Time.at high_bits_hex / 1000.0
9
+ end
10
+ end
11
+ end
12
+ end
data/lib/dial/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dial
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.4"
5
5
  end
data/lib/dial.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "dial/version"
3
+ require_relative "dial/constants"
4
+ require_relative "dial/util"
5
+
4
6
  require_relative "dial/railtie"
5
7
  require_relative "dial/engine"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dial
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Young
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2024-11-10 00:00:00.000000000 Z
10
+ date: 2024-12-27 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: railties
@@ -75,14 +75,42 @@ dependencies:
75
75
  requirements:
76
76
  - - "~>"
77
77
  - !ruby/object:Gem::Version
78
- version: '1.3'
78
+ version: '1.5'
79
79
  type: :runtime
80
80
  prerelease: false
81
81
  version_requirements: !ruby/object:Gem::Requirement
82
82
  requirements:
83
83
  - - "~>"
84
84
  - !ruby/object:Gem::Version
85
- version: '1.3'
85
+ version: '1.5'
86
+ - !ruby/object:Gem::Dependency
87
+ name: prosopite
88
+ requirement: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - "~>"
91
+ - !ruby/object:Gem::Version
92
+ version: '1.4'
93
+ type: :runtime
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '1.4'
100
+ - !ruby/object:Gem::Dependency
101
+ name: pg_query
102
+ requirement: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - "~>"
105
+ - !ruby/object:Gem::Version
106
+ version: '5.1'
107
+ type: :runtime
108
+ prerelease: false
109
+ version_requirements: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - "~>"
112
+ - !ruby/object:Gem::Version
113
+ version: '5.1'
86
114
  email:
87
115
  - djry1999@gmail.com
88
116
  executables: []
@@ -99,10 +127,12 @@ files:
99
127
  - lib/dial/engine.rb
100
128
  - lib/dial/engine/routes.rb
101
129
  - lib/dial/middleware.rb
102
- - lib/dial/panel.rb
103
- - lib/dial/rails_stat.rb
130
+ - lib/dial/middleware/panel.rb
131
+ - lib/dial/middleware/rails_stat.rb
132
+ - lib/dial/middleware/ruby_stat.rb
133
+ - lib/dial/prosopite_logger.rb
104
134
  - lib/dial/railtie.rb
105
- - lib/dial/ruby_stat.rb
135
+ - lib/dial/util.rb
106
136
  - lib/dial/version.rb
107
137
  homepage: https://github.com/joshuay03/dial
108
138
  licenses:
@@ -124,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
154
  - !ruby/object:Gem::Version
125
155
  version: '0'
126
156
  requirements: []
127
- rubygems_version: 3.6.0.dev
157
+ rubygems_version: 3.6.2
128
158
  specification_version: 4
129
159
  summary: A modern Rails profiler
130
160
  test_files: []