dial 0.1.3 → 0.1.5
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 +4 -4
 - data/CHANGELOG.md +9 -0
 - data/README.md +17 -4
 - data/dial.gemspec +3 -1
 - data/lib/dial/constants.rb +8 -1
 - data/lib/dial/middleware/panel.rb +62 -5
 - data/lib/dial/middleware.rb +91 -17
 - data/lib/dial/prosopite_logger.rb +6 -0
 - data/lib/dial/railtie.rb +23 -0
 - data/lib/dial/util.rb +12 -0
 - data/lib/dial/version.rb +1 -1
 - data/lib/dial.rb +3 -1
 - metadata +35 -5
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 82171550e05c2bc884c0ea9a55e6464f42d9bfef043af62e123c03fdbce943b6
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: f7c98017bbcaa66ad376c0b01570007f6b5b70c36ef25843a34254b0e4c82714
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 64e51ddaf1029231903836e08c8943afe75df9ec068f4506cba3a85e4c2a5059651af66e8ce3c797132f0ee1943c773abcd52a8ea9fc13fec8280253dbf5dfb3
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: cf6d09efec8cd1e581d0b13a91cd6bfce0c1d86612d9b2bf778c01ac6f1766c40fe122eeca19e6133749c396eec2bea34610be2e3d6cd231a4c6eaeebf0d99d6
         
     | 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -1,5 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ## [Unreleased]
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            ## [0.1.5] - 2025-01-24
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            - UI: Fix overflow and add vertical scroll
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            ## [0.1.4] - 2024-12-27
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            - Use vernier memory usage and rails hooks by default
         
     | 
| 
      
 10 
     | 
    
         
            +
            - Add support for N+1 detection with prosopite
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
       3 
12 
     | 
    
         
             
            ## [0.1.3] - 2024-11-14
         
     | 
| 
       4 
13 
     | 
    
         | 
| 
       5 
14 
     | 
    
         
             
            - Enable allocation profiling by default
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -7,17 +7,30 @@ WIP 
     | 
|
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            A modern profiler for Rails applications.
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
      
 10 
     | 
    
         
            +
            Check out the demo:
         
     | 
| 
      
 11 
     | 
    
         
            +
            [](https://youtu.be/LPXtfJ0c284)
         
     | 
| 
       11 
12 
     | 
    
         | 
| 
       12 
13 
     | 
    
         
             
            ## Installation
         
     | 
| 
       13 
14 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
      
 15 
     | 
    
         
            +
            1. Add the gem to your Rails application's Gemfile (adjust the `require` option to match your server of choice):
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 18 
     | 
    
         
            +
            # require in just the server process
         
     | 
| 
      
 19 
     | 
    
         
            +
            gem "dial", require: !!($PROGRAM_NAME =~ /puma/)
         
     | 
| 
      
 20 
     | 
    
         
            +
            ```
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            2. Install the gem:
         
     | 
| 
       15 
23 
     | 
    
         | 
| 
       16 
24 
     | 
    
         
             
            ```bash
         
     | 
| 
       17 
     | 
    
         
            -
            bundle  
     | 
| 
      
 25 
     | 
    
         
            +
            bundle install
         
     | 
| 
       18 
26 
     | 
    
         
             
            ```
         
     | 
| 
       19 
27 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
      
 28 
     | 
    
         
            +
            3. Mount the engine in your `config/routes.rb` file:
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 31 
     | 
    
         
            +
            # this will mount the engine at /dial
         
     | 
| 
      
 32 
     | 
    
         
            +
            mount Dial::Engine, at: "/" if Object.const_defined?("Dial::Engine")
         
     | 
| 
      
 33 
     | 
    
         
            +
            ```
         
     | 
| 
       21 
34 
     | 
    
         | 
| 
       22 
35 
     | 
    
         
             
            ## Development
         
     | 
| 
       23 
36 
     | 
    
         | 
    
        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. 
     | 
| 
      
 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
         
     | 
    
        data/lib/dial/constants.rb
    CHANGED
    
    | 
         @@ -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"
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              PROFILE_OUT_STALE_SECONDS = 60 * 60
         
     | 
| 
      
 9 
     | 
    
         
            +
              PROFILE_OUT_RELATIVE_DIRNAME = "tmp/dial/profiles/"
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              PROSOPITE_IGNORE_QUERIES = [/schema_migrations/]
         
     | 
| 
      
 12 
     | 
    
         
            +
              PROSOPITE_LOG_RELATIVE_PATHNAME = "log/dial/prosopite.log"
         
     | 
| 
       6 
13 
     | 
    
         
             
            end
         
     | 
| 
         @@ -5,7 +5,7 @@ require "uri" 
     | 
|
| 
       5 
5 
     | 
    
         
             
            module Dial
         
     | 
| 
       6 
6 
     | 
    
         
             
              class Panel
         
     | 
| 
       7 
7 
     | 
    
         
             
                class << self
         
     | 
| 
       8 
     | 
    
         
            -
                  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
         
     | 
| 
       9 
9 
     | 
    
         
             
                    <<~HTML
         
     | 
| 
       10 
10 
     | 
    
         
             
                      <style>#{style}</style>
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
         @@ -21,7 +21,16 @@ module Dial 
     | 
|
| 
       21 
21 
     | 
    
         
             
                          <span>#{formatted_ruby_version}</span>
         
     | 
| 
       22 
22 
     | 
    
         
             
                        </div>
         
     | 
| 
       23 
23 
     | 
    
         | 
| 
      
 24 
     | 
    
         
            +
                        <hr>
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
       24 
26 
     | 
    
         
             
                        <div id="dial-details">
         
     | 
| 
      
 27 
     | 
    
         
            +
                          <details>
         
     | 
| 
      
 28 
     | 
    
         
            +
                            <summary>N+1s</summary>
         
     | 
| 
      
 29 
     | 
    
         
            +
                            <div class="section query-logs">
         
     | 
| 
      
 30 
     | 
    
         
            +
                              #{formatted_query_logs query_logs}
         
     | 
| 
      
 31 
     | 
    
         
            +
                            </div>
         
     | 
| 
      
 32 
     | 
    
         
            +
                          </details>
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
       25 
34 
     | 
    
         
             
                          <hr>
         
     | 
| 
       26 
35 
     | 
    
         | 
| 
       27 
36 
     | 
    
         
             
                          <details>
         
     | 
| 
         @@ -31,6 +40,8 @@ module Dial 
     | 
|
| 
       31 
40 
     | 
    
         
             
                            </div>
         
     | 
| 
       32 
41 
     | 
    
         
             
                          </details>
         
     | 
| 
       33 
42 
     | 
    
         | 
| 
      
 43 
     | 
    
         
            +
                          <hr>
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
       34 
45 
     | 
    
         
             
                          <details>
         
     | 
| 
       35 
46 
     | 
    
         
             
                            <summary>RubyVM stat</summary>
         
     | 
| 
       36 
47 
     | 
    
         
             
                            <div class="section">
         
     | 
| 
         @@ -38,6 +49,8 @@ module Dial 
     | 
|
| 
       38 
49 
     | 
    
         
             
                            </div>
         
     | 
| 
       39 
50 
     | 
    
         
             
                          </details>
         
     | 
| 
       40 
51 
     | 
    
         | 
| 
      
 52 
     | 
    
         
            +
                          <hr>
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
       41 
54 
     | 
    
         
             
                          <details>
         
     | 
| 
       42 
55 
     | 
    
         
             
                            <summary>GC stat</summary>
         
     | 
| 
       43 
56 
     | 
    
         
             
                            <div class="section">
         
     | 
| 
         @@ -45,6 +58,8 @@ module Dial 
     | 
|
| 
       45 
58 
     | 
    
         
             
                            </div>
         
     | 
| 
       46 
59 
     | 
    
         
             
                          </details>
         
     | 
| 
       47 
60 
     | 
    
         | 
| 
      
 61 
     | 
    
         
            +
                          <hr>
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
       48 
63 
     | 
    
         
             
                          <details>
         
     | 
| 
       49 
64 
     | 
    
         
             
                            <summary>GC stat heap</summary>
         
     | 
| 
       50 
65 
     | 
    
         
             
                            <div class="section">
         
     | 
| 
         @@ -63,6 +78,8 @@ module Dial 
     | 
|
| 
       63 
78 
     | 
    
         
             
                  def style
         
     | 
| 
       64 
79 
     | 
    
         
             
                    <<~CSS
         
     | 
| 
       65 
80 
     | 
    
         
             
                      #dial {
         
     | 
| 
      
 81 
     | 
    
         
            +
                        max-height: 50%;
         
     | 
| 
      
 82 
     | 
    
         
            +
                        max-width: 50%;
         
     | 
| 
       66 
83 
     | 
    
         
             
                        z-index: 9999;
         
     | 
| 
       67 
84 
     | 
    
         
             
                        position: fixed;
         
     | 
| 
       68 
85 
     | 
    
         
             
                        bottom: 0;
         
     | 
| 
         @@ -84,6 +101,7 @@ module Dial 
     | 
|
| 
       84 
101 
     | 
    
         | 
| 
       85 
102 
     | 
    
         
             
                        #dial-details {
         
     | 
| 
       86 
103 
     | 
    
         
             
                          display: none;
         
     | 
| 
      
 104 
     | 
    
         
            +
                          overflow-y: auto;
         
     | 
| 
       87 
105 
     | 
    
         
             
                        }
         
     | 
| 
       88 
106 
     | 
    
         | 
| 
       89 
107 
     | 
    
         
             
                        .section {
         
     | 
| 
         @@ -92,6 +110,15 @@ module Dial 
     | 
|
| 
       92 
110 
     | 
    
         
             
                          margin: 0.25rem 0 0 0;
         
     | 
| 
       93 
111 
     | 
    
         
             
                        }
         
     | 
| 
       94 
112 
     | 
    
         | 
| 
      
 113 
     | 
    
         
            +
                        .query-logs {
         
     | 
| 
      
 114 
     | 
    
         
            +
                          padding-left: 0.75rem;
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                          details {
         
     | 
| 
      
 117 
     | 
    
         
            +
                            margin-top: 0;
         
     | 
| 
      
 118 
     | 
    
         
            +
                            margin-bottom: 0.25rem;
         
     | 
| 
      
 119 
     | 
    
         
            +
                          }
         
     | 
| 
      
 120 
     | 
    
         
            +
                        }
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
       95 
122 
     | 
    
         
             
                        span {
         
     | 
| 
       96 
123 
     | 
    
         
             
                          text-align: left;
         
     | 
| 
       97 
124 
     | 
    
         
             
                        }
         
     | 
| 
         @@ -99,6 +126,7 @@ module Dial 
     | 
|
| 
       99 
126 
     | 
    
         
             
                        hr {
         
     | 
| 
       100 
127 
     | 
    
         
             
                          width: -moz-available;
         
     | 
| 
       101 
128 
     | 
    
         
             
                          margin: 0.65rem 0 0 0;
         
     | 
| 
      
 129 
     | 
    
         
            +
                          background-color: black;
         
     | 
| 
       102 
130 
     | 
    
         
             
                        }
         
     | 
| 
       103 
131 
     | 
    
         | 
| 
       104 
132 
     | 
    
         
             
                        details {
         
     | 
| 
         @@ -118,10 +146,22 @@ module Dial 
     | 
|
| 
       118 
146 
     | 
    
         
             
                    <<~JS
         
     | 
| 
       119 
147 
     | 
    
         
             
                      const dialPreview = document.getElementById("dial-preview");
         
     | 
| 
       120 
148 
     | 
    
         
             
                      const dialDetails = document.getElementById("dial-details");
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
       121 
150 
     | 
    
         
             
                      dialPreview.addEventListener("click", () => {
         
     | 
| 
       122 
151 
     | 
    
         
             
                        const collapsed = ["", "none"].includes(dialDetails.style.display);
         
     | 
| 
       123 
152 
     | 
    
         
             
                        dialDetails.style.display = collapsed ? "block" : "none";
         
     | 
| 
       124 
153 
     | 
    
         
             
                      });
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
                      document.addEventListener("click", (event) => {
         
     | 
| 
      
 156 
     | 
    
         
            +
                        if (!dialPreview.contains(event.target) && !dialDetails.contains(event.target)) {
         
     | 
| 
      
 157 
     | 
    
         
            +
                          dialDetails.style.display = "none";
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
                          const detailsElements = dialDetails.querySelectorAll("details");
         
     | 
| 
      
 160 
     | 
    
         
            +
                          detailsElements.forEach(detail => {
         
     | 
| 
      
 161 
     | 
    
         
            +
                            detail.removeAttribute("open");
         
     | 
| 
      
 162 
     | 
    
         
            +
                          });
         
     | 
| 
      
 163 
     | 
    
         
            +
                        }
         
     | 
| 
      
 164 
     | 
    
         
            +
                      });
         
     | 
| 
       125 
165 
     | 
    
         
             
                    JS
         
     | 
| 
       126 
166 
     | 
    
         
             
                  end
         
     | 
| 
       127 
167 
     | 
    
         | 
| 
         @@ -140,10 +180,10 @@ module Dial 
     | 
|
| 
       140 
180 
     | 
    
         
             
                  end
         
     | 
| 
       141 
181 
     | 
    
         | 
| 
       142 
182 
     | 
    
         
             
                  def formatted_profile_output env, profile_out_filename
         
     | 
| 
      
 183 
     | 
    
         
            +
                    url_base = ::Rails.application.routes.url_helpers.dial_url host: env[::Rack::HTTP_HOST]
         
     | 
| 
      
 184 
     | 
    
         
            +
                    prefix = "/" unless url_base.end_with? "/"
         
     | 
| 
       143 
185 
     | 
    
         
             
                    uuid = profile_out_filename.delete_suffix ".json"
         
     | 
| 
       144 
     | 
    
         
            -
                     
     | 
| 
       145 
     | 
    
         
            -
                    base_url = ::Rails.application.routes.url_helpers.dial_url host: host
         
     | 
| 
       146 
     | 
    
         
            -
                    profile_out_url = URI.encode_www_form_component base_url + "dial/profile?uuid=#{uuid}"
         
     | 
| 
      
 186 
     | 
    
         
            +
                    profile_out_url = URI.encode_www_form_component url_base + "#{prefix}dial/profile?uuid=#{uuid}"
         
     | 
| 
       147 
187 
     | 
    
         | 
| 
       148 
188 
     | 
    
         
             
                    "<a href='https://vernier.prof/from-url/#{profile_out_url}' target='_blank'>View profile</a>"
         
     | 
| 
       149 
189 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -163,7 +203,6 @@ module Dial 
     | 
|
| 
       163 
203 
     | 
    
         
             
                  def formatted_server_timing server_timing
         
     | 
| 
       164 
204 
     | 
    
         
             
                    if server_timing.any?
         
     | 
| 
       165 
205 
     | 
    
         
             
                      server_timing
         
     | 
| 
       166 
     | 
    
         
            -
                        # TODO: Nested sorting
         
     | 
| 
       167 
206 
     | 
    
         
             
                        .sort_by { |_, timing| -timing }
         
     | 
| 
       168 
207 
     | 
    
         
             
                        .map { |event, timing| "<span><b>#{event}:</b> #{timing}</span>" }.join
         
     | 
| 
       169 
208 
     | 
    
         
             
                    else
         
     | 
| 
         @@ -171,6 +210,24 @@ module Dial 
     | 
|
| 
       171 
210 
     | 
    
         
             
                    end
         
     | 
| 
       172 
211 
     | 
    
         
             
                  end
         
     | 
| 
       173 
212 
     | 
    
         | 
| 
      
 213 
     | 
    
         
            +
                  def formatted_query_logs query_logs
         
     | 
| 
      
 214 
     | 
    
         
            +
                    if query_logs.any?
         
     | 
| 
      
 215 
     | 
    
         
            +
                      query_logs.map do |(queries, stack_lines)|
         
     | 
| 
      
 216 
     | 
    
         
            +
                        <<~HTML
         
     | 
| 
      
 217 
     | 
    
         
            +
                          <details>
         
     | 
| 
      
 218 
     | 
    
         
            +
                            <summary>#{queries.shift}</summary>
         
     | 
| 
      
 219 
     | 
    
         
            +
                            <div class="section query-logs">
         
     | 
| 
      
 220 
     | 
    
         
            +
                              #{queries.map { |query| "<span>#{query}</span>" }.join}
         
     | 
| 
      
 221 
     | 
    
         
            +
                              #{stack_lines.map { |stack_line| "<span>#{stack_line}</span>" }.join}
         
     | 
| 
      
 222 
     | 
    
         
            +
                            </div>
         
     | 
| 
      
 223 
     | 
    
         
            +
                          </details>
         
     | 
| 
      
 224 
     | 
    
         
            +
                        HTML
         
     | 
| 
      
 225 
     | 
    
         
            +
                      end.join
         
     | 
| 
      
 226 
     | 
    
         
            +
                    else
         
     | 
| 
      
 227 
     | 
    
         
            +
                      "NA"
         
     | 
| 
      
 228 
     | 
    
         
            +
                    end
         
     | 
| 
      
 229 
     | 
    
         
            +
                  end
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
       174 
231 
     | 
    
         
             
                  def formatted_ruby_vm_stat ruby_vm_stat
         
     | 
| 
       175 
232 
     | 
    
         
             
                    ruby_vm_stat.map { |key, value| "<span><b>#{key}:</b> #{value}</span>" }.join
         
     | 
| 
       176 
233 
     | 
    
         
             
                  end
         
     | 
    
        data/lib/dial/middleware.rb
    CHANGED
    
    | 
         @@ -1,8 +1,10 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            require "securerandom"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
       3 
5 
     | 
    
         
             
            require "vernier"
         
     | 
| 
      
 6 
     | 
    
         
            +
            require "prosopite"
         
     | 
| 
       4 
7 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
            require_relative "constants"
         
     | 
| 
       6 
8 
     | 
    
         
             
            require_relative "middleware/panel"
         
     | 
| 
       7 
9 
     | 
    
         
             
            require_relative "middleware/ruby_stat"
         
     | 
| 
       8 
10 
     | 
    
         
             
            require_relative "middleware/rails_stat"
         
     | 
| 
         @@ -19,38 +21,36 @@ module Dial 
     | 
|
| 
       19 
21 
     | 
    
         
             
                def call env
         
     | 
| 
       20 
22 
     | 
    
         
             
                  start_time = Process.clock_gettime Process::CLOCK_MONOTONIC
         
     | 
| 
       21 
23 
     | 
    
         | 
| 
       22 
     | 
    
         
            -
                   
     | 
| 
       23 
     | 
    
         
            -
                   
     | 
| 
       24 
     | 
    
         
            -
                  gc_stat_heap_before = GC.stat_heap
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       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 
     | 
    
         
            -
                   
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
      
 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 
     | 
    
         | 
| 
      
 43 
     | 
    
         
            +
                  query_logs = clear_query_logs!
         
     | 
| 
      
 44 
     | 
    
         
            +
                  remove_stale_profile_out_files!
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
       41 
46 
     | 
    
         
             
                  finish_time = Process.clock_gettime Process::CLOCK_MONOTONIC
         
     | 
| 
       42 
47 
     | 
    
         
             
                  env[REQUEST_TIMING_HEADER] = ((finish_time - start_time) * 1_000).round 2
         
     | 
| 
       43 
48 
     | 
    
         | 
| 
       44 
     | 
    
         
            -
                  ruby_vm_stat = ruby_vm_stat_diff ruby_vm_stat_before, RubyVM.stat
         
     | 
| 
       45 
     | 
    
         
            -
                  gc_stat = gc_stat_diff gc_stat_before, GC.stat
         
     | 
| 
       46 
     | 
    
         
            -
                  gc_stat_heap = gc_stat_heap_diff gc_stat_heap_before, GC.stat_heap
         
     | 
| 
       47 
     | 
    
         
            -
                  server_timing = server_timing headers
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
49 
     | 
    
         
             
                  body = String.new.tap do |str|
         
     | 
| 
       50 
50 
     | 
    
         
             
                    rack_body.each { |chunk| str << chunk }
         
     | 
| 
       51 
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, gc_stat, gc_stat_heap, 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,79 @@ 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 = section = count = nil
         
     | 
| 
      
 97 
     | 
    
         
            +
                      file.each_line do |line|
         
     | 
| 
      
 98 
     | 
    
         
            +
                        entry, section, count = process_query_log_line line, entry, section, count
         
     | 
| 
      
 99 
     | 
    
         
            +
                        query_logs << entry if entry && section.nil?
         
     | 
| 
      
 100 
     | 
    
         
            +
                      end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                      file.truncate 0
         
     | 
| 
      
 103 
     | 
    
         
            +
                      file.rewind
         
     | 
| 
      
 104 
     | 
    
         
            +
                    end
         
     | 
| 
      
 105 
     | 
    
         
            +
                  end
         
     | 
| 
      
 106 
     | 
    
         
            +
                end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                def process_query_log_line line, entry, section, count
         
     | 
| 
      
 109 
     | 
    
         
            +
                  case line
         
     | 
| 
      
 110 
     | 
    
         
            +
                  when /N\+1 queries detected/
         
     | 
| 
      
 111 
     | 
    
         
            +
                    [[[],[]], :queries, 0]
         
     | 
| 
      
 112 
     | 
    
         
            +
                  when /Call stack/
         
     | 
| 
      
 113 
     | 
    
         
            +
                    entry.first << "+ #{count - 5} more queries" if count > 5
         
     | 
| 
      
 114 
     | 
    
         
            +
                    [entry, :call_stack, count]
         
     | 
| 
      
 115 
     | 
    
         
            +
                  else
         
     | 
| 
      
 116 
     | 
    
         
            +
                    case section
         
     | 
| 
      
 117 
     | 
    
         
            +
                    when :queries
         
     | 
| 
      
 118 
     | 
    
         
            +
                      count += 1
         
     | 
| 
      
 119 
     | 
    
         
            +
                      entry.first << line.strip if count <= 5
         
     | 
| 
      
 120 
     | 
    
         
            +
                      [entry, :queries, count]
         
     | 
| 
      
 121 
     | 
    
         
            +
                    when :call_stack
         
     | 
| 
      
 122 
     | 
    
         
            +
                      if line.strip.empty?
         
     | 
| 
      
 123 
     | 
    
         
            +
                        [entry, nil, count]
         
     | 
| 
      
 124 
     | 
    
         
            +
                      else
         
     | 
| 
      
 125 
     | 
    
         
            +
                        entry.last << line.strip
         
     | 
| 
      
 126 
     | 
    
         
            +
                        [entry, section, count]
         
     | 
| 
      
 127 
     | 
    
         
            +
                      end
         
     | 
| 
      
 128 
     | 
    
         
            +
                    end
         
     | 
| 
      
 129 
     | 
    
         
            +
                  end
         
     | 
| 
      
 130 
     | 
    
         
            +
                end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                def query_log_pathname
         
     | 
| 
      
 133 
     | 
    
         
            +
                  @_query_log_dir_pathname ||= ::Rails.root.join PROSOPITE_LOG_RELATIVE_PATHNAME
         
     | 
| 
      
 134 
     | 
    
         
            +
                end
         
     | 
| 
       61 
135 
     | 
    
         
             
              end
         
     | 
| 
       62 
136 
     | 
    
         
             
            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
    
    
    
        data/lib/dial/version.rb
    CHANGED
    
    
    
        data/lib/dial.rb
    CHANGED
    
    
    
        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. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.1.5
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Joshua Young
         
     | 
| 
       8 
8 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       9 
9 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       10 
     | 
    
         
            -
            date:  
     | 
| 
      
 10 
     | 
    
         
            +
            date: 2025-01-24 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. 
     | 
| 
      
 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. 
     | 
| 
      
 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: []
         
     | 
| 
         @@ -102,7 +130,9 @@ files: 
     | 
|
| 
       102 
130 
     | 
    
         
             
            - lib/dial/middleware/panel.rb
         
     | 
| 
       103 
131 
     | 
    
         
             
            - lib/dial/middleware/rails_stat.rb
         
     | 
| 
       104 
132 
     | 
    
         
             
            - lib/dial/middleware/ruby_stat.rb
         
     | 
| 
      
 133 
     | 
    
         
            +
            - lib/dial/prosopite_logger.rb
         
     | 
| 
       105 
134 
     | 
    
         
             
            - lib/dial/railtie.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. 
     | 
| 
      
 157 
     | 
    
         
            +
            rubygems_version: 3.6.2
         
     | 
| 
       128 
158 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       129 
159 
     | 
    
         
             
            summary: A modern Rails profiler
         
     | 
| 
       130 
160 
     | 
    
         
             
            test_files: []
         
     |