dial 0.3.0 → 0.3.2

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: 42f0f94ef6fdc4992e56f9b1938f464916c2ac36ded2ae17a506fc3798cda278
4
- data.tar.gz: 05e9b4db37fa643be44ca3b9800d44ecc79dbe1b69209d4978e13de1dbec82d6
3
+ metadata.gz: 1cf2ace9f735e0ffd4c290b742bbf7f89f322babb96636e942fe1faaf92a8e45
4
+ data.tar.gz: '06279e4a580959080df277abe1a8488bca20f50276d9221ca399366f570e1426'
5
5
  SHA512:
6
- metadata.gz: 6f071e302b7b7f83395a3f4e796d9b8cb3b99138dcd9b67c7cabfd57dea537d197266e01f4789644c06c482b72badc6f6c858bb28913631959c9255ebf162536
7
- data.tar.gz: f6782c98fde560a03f29aa95bdae546e1d1aae0388b6a2403617d229d15cebe3d4ab2d36d606a4ede4b5b4ff43c9f9690336716865b22eb526b9a706f98906a0
6
+ metadata.gz: bde524497181a25dbeddc54f8f04ff128714844a5f2b6d8c84ae569bf4d45cb39942dddbe0d687e63c7b3c23f590410128de4abfffa69e5ee41923be4a73b6c1
7
+ data.tar.gz: e2bd5aef0ee0975a8e9c227a77296f40811d558251035771177c11f2128b599d905644186237280b3718f64ff65b31b834e01cfd222e5baba0077a53ee631451
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.2] - 2025-05-14
4
+
5
+ - Consolidate railtie initializers
6
+
7
+ ## [0.3.1] - 2025-05-03
8
+
9
+ - Only show truncated summary + one full query in N+1 logs
10
+ - Fix parsing of multiline N+1 query logs
11
+ - Truncate summary N+1 queries to 100 chars
12
+
3
13
  ## [0.3.0] - 2025-05-02
4
14
 
5
15
  - Require rails 7.1.0 or later
@@ -31,6 +31,7 @@ module Dial
31
31
 
32
32
  def freeze
33
33
  @options.freeze
34
+
34
35
  super
35
36
  end
36
37
  end
@@ -11,6 +11,7 @@ module Dial
11
11
 
12
12
  HTTP_ACCEPT = "HTTP_ACCEPT"
13
13
  CONTENT_TYPE = ::Rack::CONTENT_TYPE
14
+ CONTENT_TYPE_HTML = "text/html"
14
15
  CONTENT_LENGTH = ::Rack::CONTENT_LENGTH
15
16
  NONCE = ::ActionDispatch::ContentSecurityPolicy::Request::NONCE
16
17
  REQUEST_TIMING = "dial_request_timing"
@@ -20,6 +21,7 @@ module Dial
20
21
  VERNIER_INTERVAL = 200
21
22
  VERNIER_ALLOCATION_INTERVAL = 2_000
22
23
  VERNIER_PROFILE_OUT_RELATIVE_DIRNAME = "tmp/dial/profiles"
24
+ VERNIER_PROFILE_OUT_FILE_EXTENSION = ".json.gz"
23
25
  VERNIER_VIEWER_URL = "https://vernier.prof"
24
26
 
25
27
  PROSOPITE_IGNORE_QUERIES = [/schema_migrations/i].freeze
@@ -4,7 +4,7 @@ Dial::Engine.routes.draw do
4
4
  scope path: "/dial", as: "dial" do
5
5
  get "profile", to: lambda { |env|
6
6
  uuid = env[::Rack::QUERY_STRING].sub "uuid=", ""
7
- path = String ::Rails.root.join Dial::VERNIER_PROFILE_OUT_RELATIVE_DIRNAME, "#{uuid}.json.gz"
7
+ path = String ::Rails.root.join Dial::VERNIER_PROFILE_OUT_RELATIVE_DIRNAME, (uuid + VERNIER_PROFILE_OUT_FILE_EXTENSION)
8
8
 
9
9
  if File.exist? path
10
10
  [
@@ -4,6 +4,8 @@ require "uri"
4
4
 
5
5
  module Dial
6
6
  class Panel
7
+ QUERY_CHARS_TRUNCATION_THRESHOLD = 100
8
+
7
9
  class << self
8
10
  def html env, headers, profile_out_filename, query_logs, ruby_vm_stat, gc_stat, gc_stat_heap, server_timing
9
11
  <<~HTML
@@ -190,7 +192,7 @@ module Dial
190
192
  def formatted_profile_output env, profile_out_filename
191
193
  url_base = ::Rails.application.routes.url_helpers.dial_url host: env[::Rack::HTTP_HOST]
192
194
  prefix = "/" unless url_base.end_with? "/"
193
- uuid = profile_out_filename.delete_suffix ".json.gz"
195
+ uuid = profile_out_filename.delete_suffix VERNIER_PROFILE_OUT_FILE_EXTENSION
194
196
  profile_out_url = URI.encode_www_form_component url_base + "#{prefix}dial/profile?uuid=#{uuid}"
195
197
 
196
198
  "<a href='https://vernier.prof/from-url/#{profile_out_url}' target='_blank'>View profile</a>"
@@ -223,7 +225,7 @@ module Dial
223
225
  query_logs.map do |(queries, stack_lines)|
224
226
  <<~HTML
225
227
  <details>
226
- <summary>#{queries.shift}</summary>
228
+ <summary>#{truncated_query queries.first}</summary>
227
229
  <div class="section query-logs">
228
230
  #{queries.map { |query| "<span>#{query}</span>" }.join}
229
231
  #{stack_lines.map { |stack_line| "<span>#{stack_line}</span>" }.join}
@@ -236,6 +238,12 @@ module Dial
236
238
  end
237
239
  end
238
240
 
241
+ def truncated_query query
242
+ return query if query.length <= QUERY_CHARS_TRUNCATION_THRESHOLD
243
+
244
+ query[0...QUERY_CHARS_TRUNCATION_THRESHOLD] + "..."
245
+ end
246
+
239
247
  def formatted_ruby_vm_stat ruby_vm_stat
240
248
  ruby_vm_stat.map { |key, value| "<span><b>#{key}:</b> #{value}</span>" }.join
241
249
  end
@@ -3,6 +3,7 @@
3
3
  require "vernier"
4
4
  require "prosopite"
5
5
 
6
+ require_relative "prosopite"
6
7
  require_relative "middleware/panel"
7
8
  require_relative "middleware/ruby_stat"
8
9
  require_relative "middleware/rails_stat"
@@ -12,20 +13,18 @@ module Dial
12
13
  include RubyStat
13
14
  include RailsStat
14
15
 
15
- HTML_CONTENT_TYPE = "text/html"
16
-
17
16
  def initialize app
18
17
  @app = app
19
18
  end
20
19
 
21
20
  def call env
22
- unless env[HTTP_ACCEPT]&.include? HTML_CONTENT_TYPE
21
+ unless env[HTTP_ACCEPT]&.include? CONTENT_TYPE_HTML
23
22
  return @app.call env
24
23
  end
25
24
 
26
25
  start_time = Process.clock_gettime Process::CLOCK_MONOTONIC
27
26
 
28
- profile_out_filename = "#{Util.uuid}_vernier.json.gz"
27
+ profile_out_filename = "#{Util.uuid}_vernier" + VERNIER_PROFILE_OUT_FILE_EXTENSION
29
28
  profile_out_pathname = "#{profile_out_dir_pathname}/#{profile_out_filename}"
30
29
 
31
30
  status, headers, rack_body, ruby_vm_stat, gc_stat, gc_stat_heap, vernier_result = nil
@@ -40,7 +39,7 @@ module Dial
40
39
  end
41
40
  server_timing = server_timing headers
42
41
 
43
- unless headers[CONTENT_TYPE]&.include? HTML_CONTENT_TYPE
42
+ unless headers[CONTENT_TYPE]&.include? CONTENT_TYPE_HTML
44
43
  return [status, headers, rack_body]
45
44
  end
46
45
 
@@ -106,13 +105,13 @@ module Dial
106
105
  when /N\+1 queries detected/
107
106
  [[[],[]], :queries, 0]
108
107
  when /Call stack/
109
- entry.first << "+ #{count - 5} more queries" if count > 5
108
+ entry.first << "+ #{count - 1} more queries" if count > 1
110
109
  [entry, :call_stack, count]
111
110
  else
112
111
  case section
113
112
  when :queries
114
113
  count += 1
115
- entry.first << line.strip if count <= 5
114
+ entry.first << line.strip if count == 1
116
115
  [entry, :queries, count]
117
116
  when :call_stack
118
117
  if line.strip.empty?
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/filters"
4
+
5
+ module Dial
6
+ module Prosopite
7
+ def send_notifications
8
+ tc[:prosopite_notifications] = tc[:prosopite_notifications].to_h do |queries, kaller|
9
+ [queries.map { |query| query.squish }, kaller]
10
+ end
11
+
12
+ super
13
+ end
14
+ end
15
+ end
16
+
17
+ module ::Prosopite
18
+ class << self
19
+ prepend Dial::Prosopite
20
+ end
21
+ end
data/lib/dial/railtie.rb CHANGED
@@ -9,36 +9,27 @@ require_relative "prosopite_logger"
9
9
 
10
10
  module Dial
11
11
  class Railtie < ::Rails::Railtie
12
- initializer "dial.use_middleware", after: :load_config_initializers do |app|
12
+ initializer "dial.setup", after: :load_config_initializers do |app|
13
+ # use middleware
13
14
  app.middleware.insert_before 0, Middleware
14
- end
15
-
16
- initializer "dial.set_up_vernier", after: :load_config_initializers do |app|
17
- app.config.after_initialize do
18
- FileUtils.mkdir_p ::Rails.root.join VERNIER_PROFILE_OUT_RELATIVE_DIRNAME
19
- end
20
- end
21
15
 
22
- initializer "dial.clean_up_vernier_profile_out_files", after: :load_config_initializers do |app|
23
- stale_files("#{profile_out_dir_pathname}/*.json.gz").each do |profile_out_file|
16
+ # clean up stale vernier profile output files
17
+ stale_files("#{profile_out_dir_pathname}/*" + VERNIER_PROFILE_OUT_FILE_EXTENSION).each do |profile_out_file|
24
18
  File.delete profile_out_file rescue nil
25
19
  end
26
- end
27
20
 
28
- initializer "dial.set_up_prosopite", after: :load_config_initializers do |app|
29
21
  app.config.after_initialize do
22
+ # set up vernier
23
+ FileUtils.mkdir_p ::Rails.root.join VERNIER_PROFILE_OUT_RELATIVE_DIRNAME
24
+
25
+ # set up prosopite
30
26
  if ::ActiveRecord::Base.configurations.configurations.any? { |config| config.adapter == "postgresql" }
31
27
  require "pg_query"
32
28
  end
33
-
34
29
  ::Prosopite.custom_logger = ProsopiteLogger.new PROSOPITE_LOG_IO
35
- end
36
- end
37
30
 
38
- initializer "dial.setup", after: :load_config_initializers do |app|
39
- app.config.after_initialize do
31
+ # finalize configuration
40
32
  Dial._configuration.freeze
41
-
42
33
  ::Prosopite.ignore_queries = Dial._configuration.prosopite_ignore_queries
43
34
  end
44
35
  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.3.0"
4
+ VERSION = "0.3.2"
5
5
  end
data/lib/dial.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "dial/util"
4
3
  require_relative "dial/constants"
4
+ require_relative "dial/util"
5
5
 
6
6
  require_relative "dial/configuration"
7
7
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dial
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Young
@@ -113,6 +113,7 @@ files:
113
113
  - lib/dial/middleware/panel.rb
114
114
  - lib/dial/middleware/rails_stat.rb
115
115
  - lib/dial/middleware/ruby_stat.rb
116
+ - lib/dial/prosopite.rb
116
117
  - lib/dial/prosopite_logger.rb
117
118
  - lib/dial/railtie.rb
118
119
  - lib/dial/util.rb
@@ -137,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
138
  - !ruby/object:Gem::Version
138
139
  version: '0'
139
140
  requirements: []
140
- rubygems_version: 3.6.7
141
+ rubygems_version: 3.6.9
141
142
  specification_version: 4
142
143
  summary: A modern profiler for your Rails application
143
144
  test_files: []