dial 0.1.2 → 0.1.4

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.
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: []