app_profiler 0.1.3 → 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 +4 -4
- data/lib/app_profiler/middleware/upload_action.rb +13 -10
- data/lib/app_profiler/middleware.rb +4 -4
- data/lib/app_profiler/parameters.rb +35 -0
- data/lib/app_profiler/profile.rb +4 -0
- data/lib/app_profiler/railtie.rb +3 -0
- data/lib/app_profiler/request_parameters.rb +7 -7
- data/lib/app_profiler/server.rb +37 -14
- data/lib/app_profiler/storage/base_storage.rb +4 -0
- data/lib/app_profiler/storage/file_storage.rb +4 -0
- data/lib/app_profiler/storage/google_cloud_storage.rb +51 -0
- data/lib/app_profiler/version.rb +1 -1
- data/lib/app_profiler.rb +4 -0
- metadata +4 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: eaffd76839111b3280bce8241889441b85b4346121e1478cc60839f791916445
         | 
| 4 | 
            +
              data.tar.gz: f9aab66b3b52953756610b9acb8a314178ce535075d8702d4ced0624e4880409
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: c299676be9b01c62ab73885f1e6b8c6b787721acbe94266b71fec79d91e623bd599aee7b6607eb17dda0f0187a1024c43227c9bae256b660cd8155f41a9dacf4
         | 
| 7 | 
            +
              data.tar.gz: f1fd90215f29e46175ca3cd3f7bbaeed4448a40acf07e25aa1a1f7c59d8b10cc66854e0c6453cdc4367a469b03e16c8b930da6d53034e0e1d92e1b9dd4b5b5d4
         | 
| @@ -4,16 +4,19 @@ module AppProfiler | |
| 4 4 | 
             
              class Middleware
         | 
| 5 5 | 
             
                class UploadAction < BaseAction
         | 
| 6 6 | 
             
                  class << self
         | 
| 7 | 
            -
                    def call(profile, response: nil, autoredirect: nil)
         | 
| 8 | 
            -
                       | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
                         | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 7 | 
            +
                    def call(profile, response: nil, autoredirect: nil, async: false)
         | 
| 8 | 
            +
                      if async
         | 
| 9 | 
            +
                        profile.enqueue_upload
         | 
| 10 | 
            +
                        response[1][AppProfiler.profile_async_header] = true
         | 
| 11 | 
            +
                      else
         | 
| 12 | 
            +
                        profile_upload = profile.upload
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                        append_headers(
         | 
| 15 | 
            +
                          response,
         | 
| 16 | 
            +
                          upload: profile_upload,
         | 
| 17 | 
            +
                          autoredirect: autoredirect.nil? ? AppProfiler.autoredirect : autoredirect
         | 
| 18 | 
            +
                        ) if response
         | 
| 19 | 
            +
                      end
         | 
| 17 20 | 
             
                    end
         | 
| 18 21 |  | 
| 19 22 | 
             
                    private
         | 
| @@ -14,16 +14,15 @@ module AppProfiler | |
| 14 14 | 
             
                  @app = app
         | 
| 15 15 | 
             
                end
         | 
| 16 16 |  | 
| 17 | 
            -
                def call(env)
         | 
| 18 | 
            -
                  profile(env) do
         | 
| 17 | 
            +
                def call(env, params = AppProfiler::RequestParameters.new(Rack::Request.new(env)))
         | 
| 18 | 
            +
                  profile(env, params) do
         | 
| 19 19 | 
             
                    @app.call(env)
         | 
| 20 20 | 
             
                  end
         | 
| 21 21 | 
             
                end
         | 
| 22 22 |  | 
| 23 23 | 
             
                private
         | 
| 24 24 |  | 
| 25 | 
            -
                def profile(env)
         | 
| 26 | 
            -
                  params   = AppProfiler::RequestParameters.new(Rack::Request.new(env))
         | 
| 25 | 
            +
                def profile(env, params)
         | 
| 27 26 | 
             
                  response = nil
         | 
| 28 27 |  | 
| 29 28 | 
             
                  return yield unless params.valid?
         | 
| @@ -42,6 +41,7 @@ module AppProfiler | |
| 42 41 | 
             
                    profile,
         | 
| 43 42 | 
             
                    response: response,
         | 
| 44 43 | 
             
                    autoredirect: params.autoredirect,
         | 
| 44 | 
            +
                    async: params.async
         | 
| 45 45 | 
             
                  )
         | 
| 46 46 |  | 
| 47 47 | 
             
                  response
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "rack"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module AppProfiler
         | 
| 6 | 
            +
              class Parameters
         | 
| 7 | 
            +
                DEFAULT_INTERVALS = { "cpu" => 1000, "wall" => 1000, "object" => 2000 }.freeze
         | 
| 8 | 
            +
                MIN_INTERVALS = { "cpu" => 200, "wall" => 200, "object" => 400 }.freeze
         | 
| 9 | 
            +
                MODES = DEFAULT_INTERVALS.keys.freeze
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                attr_reader :autoredirect, :async
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def initialize(mode: :wall, interval: nil, ignore_gc: false, autoredirect: false, async: false, metadata: {})
         | 
| 14 | 
            +
                  @mode = mode.to_sym
         | 
| 15 | 
            +
                  @interval = [interval&.to_i || DEFAULT_INTERVALS.fetch(@mode.to_s), MIN_INTERVALS.fetch(@mode.to_s)].max
         | 
| 16 | 
            +
                  @ignore_gc = !!ignore_gc
         | 
| 17 | 
            +
                  @autoredirect = autoredirect
         | 
| 18 | 
            +
                  @metadata = { context: AppProfiler.context }.merge(metadata)
         | 
| 19 | 
            +
                  @async = async
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def valid?
         | 
| 23 | 
            +
                  true
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def to_h
         | 
| 27 | 
            +
                  {
         | 
| 28 | 
            +
                    mode: @mode,
         | 
| 29 | 
            +
                    interval: @interval,
         | 
| 30 | 
            +
                    ignore_gc: @ignore_gc,
         | 
| 31 | 
            +
                    metadata: @metadata,
         | 
| 32 | 
            +
                  }
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
    
        data/lib/app_profiler/profile.rb
    CHANGED
    
    
    
        data/lib/app_profiler/railtie.rb
    CHANGED
    
    | @@ -28,11 +28,14 @@ module AppProfiler | |
| 28 28 | 
             
                    "APP_PROFILER_SPEEDSCOPE_URL", "https://speedscope.app"
         | 
| 29 29 | 
             
                  )
         | 
| 30 30 | 
             
                  AppProfiler.profile_header = app.config.app_profiler.profile_header || "X-Profile"
         | 
| 31 | 
            +
                  AppProfiler.profile_async_header = app.config.app_profiler.profile_async_header || "X-Profile-Async"
         | 
| 31 32 | 
             
                  AppProfiler.profile_root = app.config.app_profiler.profile_root || Rails.root.join(
         | 
| 32 33 | 
             
                    "tmp", "app_profiler"
         | 
| 33 34 | 
             
                  )
         | 
| 34 35 | 
             
                  AppProfiler.context = app.config.app_profiler.context || Rails.env
         | 
| 35 36 | 
             
                  AppProfiler.profile_url_formatter = app.config.app_profiler.profile_url_formatter
         | 
| 37 | 
            +
                  AppProfiler.upload_queue_max_length = app.config.app_profiler.upload_queue_max_length || 10
         | 
| 38 | 
            +
                  AppProfiler.upload_queue_interval_secs = app.config.app_profiler.upload_queue_interval_secs || 5
         | 
| 36 39 | 
             
                end
         | 
| 37 40 |  | 
| 38 41 | 
             
                initializer "app_profiler.add_middleware" do |app|
         | 
| @@ -4,10 +4,6 @@ require "rack" | |
| 4 4 |  | 
| 5 5 | 
             
            module AppProfiler
         | 
| 6 6 | 
             
              class RequestParameters
         | 
| 7 | 
            -
                DEFAULT_INTERVALS = { "cpu" => 1000, "wall" => 1000, "object" => 2000 }.freeze
         | 
| 8 | 
            -
                MIN_INTERVALS = { "cpu" => 200, "wall" => 200, "object" => 400 }.freeze
         | 
| 9 | 
            -
                MODES = DEFAULT_INTERVALS.keys.freeze
         | 
| 10 | 
            -
             | 
| 11 7 | 
             
                def initialize(request)
         | 
| 12 8 | 
             
                  @request = request
         | 
| 13 9 | 
             
                end
         | 
| @@ -16,17 +12,21 @@ module AppProfiler | |
| 16 12 | 
             
                  query_param("autoredirect") || profile_header_param("autoredirect")
         | 
| 17 13 | 
             
                end
         | 
| 18 14 |  | 
| 15 | 
            +
                def async
         | 
| 16 | 
            +
                  query_param("async")
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 19 | 
             
                def valid?
         | 
| 20 20 | 
             
                  if mode.blank?
         | 
| 21 21 | 
             
                    return false
         | 
| 22 22 | 
             
                  end
         | 
| 23 23 |  | 
| 24 | 
            -
                  unless MODES.include?(mode)
         | 
| 24 | 
            +
                  unless Parameters::MODES.include?(mode)
         | 
| 25 25 | 
             
                    AppProfiler.logger.info("[Profiler] unsupported profiling mode=#{mode}")
         | 
| 26 26 | 
             
                    return false
         | 
| 27 27 | 
             
                  end
         | 
| 28 28 |  | 
| 29 | 
            -
                  if interval.to_i < MIN_INTERVALS[mode]
         | 
| 29 | 
            +
                  if interval.to_i < Parameters::MIN_INTERVALS[mode]
         | 
| 30 30 | 
             
                    return false
         | 
| 31 31 | 
             
                  end
         | 
| 32 32 |  | 
| @@ -56,7 +56,7 @@ module AppProfiler | |
| 56 56 | 
             
                end
         | 
| 57 57 |  | 
| 58 58 | 
             
                def interval
         | 
| 59 | 
            -
                  query_param("interval") || profile_header_param("interval") || DEFAULT_INTERVALS[mode]
         | 
| 59 | 
            +
                  query_param("interval") || profile_header_param("interval") || Parameters::DEFAULT_INTERVALS[mode]
         | 
| 60 60 | 
             
                end
         | 
| 61 61 |  | 
| 62 62 | 
             
                def request_id
         | 
    
        data/lib/app_profiler/server.rb
    CHANGED
    
    | @@ -180,6 +180,14 @@ module AppProfiler | |
| 180 180 | 
             
                  class Transport
         | 
| 181 181 | 
             
                    attr_reader :socket
         | 
| 182 182 |  | 
| 183 | 
            +
                    def initialize
         | 
| 184 | 
            +
                      start
         | 
| 185 | 
            +
                    end
         | 
| 186 | 
            +
             | 
| 187 | 
            +
                    def start
         | 
| 188 | 
            +
                      raise(NotImplementedError)
         | 
| 189 | 
            +
                    end
         | 
| 190 | 
            +
             | 
| 183 191 | 
             
                    def client
         | 
| 184 192 | 
             
                      raise(NotImplementedError)
         | 
| 185 193 | 
             
                    end
         | 
| @@ -190,9 +198,7 @@ module AppProfiler | |
| 190 198 | 
             
                  end
         | 
| 191 199 |  | 
| 192 200 | 
             
                  class UNIX < Transport
         | 
| 193 | 
            -
                    def  | 
| 194 | 
            -
                      super
         | 
| 195 | 
            -
             | 
| 201 | 
            +
                    def start
         | 
| 196 202 | 
             
                      FileUtils.mkdir_p(PROFILER_TEMPFILE_PATH)
         | 
| 197 203 | 
             
                      @socket_file = File.join(PROFILER_TEMPFILE_PATH, "app-profiler-#{Process.pid}.sock")
         | 
| 198 204 | 
             
                      File.unlink(@socket_file) if File.exist?(@socket_file) && File.socket?(@socket_file)
         | 
| @@ -213,9 +219,13 @@ module AppProfiler | |
| 213 219 | 
             
                    SERVER_ADDRESS = "127.0.0.1" # it is ONLY safe to run this bound to localhost
         | 
| 214 220 |  | 
| 215 221 | 
             
                    def initialize(port = 0)
         | 
| 222 | 
            +
                      @port_argument = port
         | 
| 216 223 | 
             
                      super()
         | 
| 224 | 
            +
                    end
         | 
| 225 | 
            +
             | 
| 226 | 
            +
                    def start
         | 
| 217 227 | 
             
                      FileUtils.mkdir_p(PROFILER_TEMPFILE_PATH)
         | 
| 218 | 
            -
                      @socket = TCPServer.new(SERVER_ADDRESS,  | 
| 228 | 
            +
                      @socket = TCPServer.new(SERVER_ADDRESS, @port_argument)
         | 
| 219 229 | 
             
                      @port = @socket.addr[1]
         | 
| 220 230 | 
             
                      @port_file = Tempfile.new("profileserver-#{Process.pid}-port-#{@port}-", PROFILER_TEMPFILE_PATH)
         | 
| 221 231 | 
             
                    end
         | 
| @@ -261,7 +271,15 @@ module AppProfiler | |
| 261 271 |  | 
| 262 272 | 
             
                    @listen_thread = Thread.new do
         | 
| 263 273 | 
             
                      loop do
         | 
| 264 | 
            -
                         | 
| 274 | 
            +
                        session = begin
         | 
| 275 | 
            +
                          @transport.socket.accept
         | 
| 276 | 
            +
                        rescue
         | 
| 277 | 
            +
                          @transport.close
         | 
| 278 | 
            +
                          @transport.start
         | 
| 279 | 
            +
                          next
         | 
| 280 | 
            +
                        end
         | 
| 281 | 
            +
             | 
| 282 | 
            +
                        Thread.new(session) do |session|
         | 
| 265 283 | 
             
                          request = session.gets
         | 
| 266 284 |  | 
| 267 285 | 
             
                          if request.nil?
         | 
| @@ -315,9 +333,12 @@ module AppProfiler | |
| 315 333 |  | 
| 316 334 | 
             
                private_constant :ProfileApplication, :ProfileServer
         | 
| 317 335 |  | 
| 336 | 
            +
                @pid = Process.pid
         | 
| 337 | 
            +
                @profile_server = nil
         | 
| 338 | 
            +
             | 
| 318 339 | 
             
                class << self
         | 
| 319 340 | 
             
                  def reset
         | 
| 320 | 
            -
                     | 
| 341 | 
            +
                    self.profile_server = nil
         | 
| 321 342 |  | 
| 322 343 | 
             
                    DEFAULTS.each do |config, value|
         | 
| 323 344 | 
             
                      class_variable_set(:"@@#{config}", value) # rubocop:disable Style/ClassVars
         | 
| @@ -327,7 +348,7 @@ module AppProfiler | |
| 327 348 | 
             
                  def start(logger = Logger.new(IO::NULL))
         | 
| 328 349 | 
             
                    return if profile_server
         | 
| 329 350 |  | 
| 330 | 
            -
                     | 
| 351 | 
            +
                    self.profile_server = ProfileServer.new(AppProfiler::Server.transport, logger)
         | 
| 331 352 | 
             
                    profile_server.serve
         | 
| 332 353 | 
             
                    profile_server
         | 
| 333 354 | 
             
                  end
         | 
| @@ -341,20 +362,22 @@ module AppProfiler | |
| 341 362 | 
             
                  def stop
         | 
| 342 363 | 
             
                    return unless profile_server
         | 
| 343 364 |  | 
| 344 | 
            -
                    profile_server | 
| 345 | 
            -
                     | 
| 365 | 
            +
                    server = profile_server
         | 
| 366 | 
            +
                    server.stop
         | 
| 367 | 
            +
                    self.profile_server = nil
         | 
| 368 | 
            +
                    server
         | 
| 346 369 | 
             
                  end
         | 
| 347 370 |  | 
| 348 371 | 
             
                  private
         | 
| 349 372 |  | 
| 350 373 | 
             
                  def profile_server
         | 
| 351 | 
            -
                     | 
| 374 | 
            +
                    @profile_server = nil if @pid != Process.pid
         | 
| 375 | 
            +
                    @profile_server
         | 
| 352 376 | 
             
                  end
         | 
| 353 377 |  | 
| 354 | 
            -
                   | 
| 355 | 
            -
             | 
| 356 | 
            -
             | 
| 357 | 
            -
                    @profile_servers ||= {}
         | 
| 378 | 
            +
                  def profile_server=(server)
         | 
| 379 | 
            +
                    @pid = Process.pid
         | 
| 380 | 
            +
                    @profile_server = server
         | 
| 358 381 | 
             
                  end
         | 
| 359 382 | 
             
                end
         | 
| 360 383 | 
             
              end
         | 
| @@ -28,8 +28,59 @@ module AppProfiler | |
| 28 28 | 
             
                      end
         | 
| 29 29 | 
             
                    end
         | 
| 30 30 |  | 
| 31 | 
            +
                    def enqueue_upload(profile)
         | 
| 32 | 
            +
                      mutex.synchronize do
         | 
| 33 | 
            +
                        process_queue_thread unless @process_queue_thread&.alive?
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                        @queue ||= init_queue
         | 
| 36 | 
            +
                        begin
         | 
| 37 | 
            +
                          @queue.push(profile, true) # non-blocking push, raises ThreadError if queue is full
         | 
| 38 | 
            +
                        rescue ThreadError
         | 
| 39 | 
            +
                          AppProfiler.logger.info("[AppProfiler] upload queue is full, profile discarded")
         | 
| 40 | 
            +
                        end
         | 
| 41 | 
            +
                      end
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                    def reset_queue # for testing
         | 
| 45 | 
            +
                      init_queue
         | 
| 46 | 
            +
                      @process_queue_thread&.kill
         | 
| 47 | 
            +
                      @process_queue_thread = nil
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
             | 
| 31 50 | 
             
                    private
         | 
| 32 51 |  | 
| 52 | 
            +
                    def mutex
         | 
| 53 | 
            +
                      @mutex ||= Mutex.new
         | 
| 54 | 
            +
                    end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    def init_queue
         | 
| 57 | 
            +
                      @queue = SizedQueue.new(AppProfiler.upload_queue_max_length)
         | 
| 58 | 
            +
                    end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                    def process_queue_thread
         | 
| 61 | 
            +
                      @process_queue_thread ||= Thread.new do
         | 
| 62 | 
            +
                        loop do
         | 
| 63 | 
            +
                          process_queue
         | 
| 64 | 
            +
                          sleep(AppProfiler.upload_queue_interval_secs)
         | 
| 65 | 
            +
                        end
         | 
| 66 | 
            +
                      end
         | 
| 67 | 
            +
                      @process_queue_thread.priority = -1 # low priority
         | 
| 68 | 
            +
                    end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                    def process_queue
         | 
| 71 | 
            +
                      queue = nil
         | 
| 72 | 
            +
                      mutex.synchronize do
         | 
| 73 | 
            +
                        break if @queue.nil? || @queue.empty?
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                        queue = @queue
         | 
| 76 | 
            +
                        init_queue
         | 
| 77 | 
            +
                      end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                      return unless queue
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                      queue.size.times { queue.pop(false).upload }
         | 
| 82 | 
            +
                    end
         | 
| 83 | 
            +
             | 
| 33 84 | 
             
                    def gcs_filename(profile)
         | 
| 34 85 | 
             
                      File.join(profile.context.to_s, profile.file.basename)
         | 
| 35 86 | 
             
                    end
         | 
    
        data/lib/app_profiler/version.rb
    CHANGED
    
    
    
        data/lib/app_profiler.rb
    CHANGED
    
    | @@ -26,6 +26,7 @@ module AppProfiler | |
| 26 26 | 
             
              end
         | 
| 27 27 |  | 
| 28 28 | 
             
              require "app_profiler/middleware"
         | 
| 29 | 
            +
              require "app_profiler/parameters"
         | 
| 29 30 | 
             
              require "app_profiler/request_parameters"
         | 
| 30 31 | 
             
              require "app_profiler/profiler"
         | 
| 31 32 | 
             
              require "app_profiler/profile"
         | 
| @@ -38,6 +39,7 @@ module AppProfiler | |
| 38 39 | 
             
              mattr_accessor :speedscope_host, default: "https://speedscope.app"
         | 
| 39 40 | 
             
              mattr_accessor :autoredirect, default: false
         | 
| 40 41 | 
             
              mattr_reader   :profile_header, default: "X-Profile"
         | 
| 42 | 
            +
              mattr_accessor :profile_async_header, default: "X-Profile-Async"
         | 
| 41 43 | 
             
              mattr_accessor :context, default: nil
         | 
| 42 44 | 
             
              mattr_reader   :profile_url_formatter,
         | 
| 43 45 | 
             
                default: DefaultProfileFormatter
         | 
| @@ -46,6 +48,8 @@ module AppProfiler | |
| 46 48 | 
             
              mattr_accessor :viewer, default: Viewer::SpeedscopeViewer
         | 
| 47 49 | 
             
              mattr_accessor :middleware, default: Middleware
         | 
| 48 50 | 
             
              mattr_accessor :server, default: Server
         | 
| 51 | 
            +
              mattr_accessor :upload_queue_max_length, default: 10
         | 
| 52 | 
            +
              mattr_accessor :upload_queue_interval_secs, default: 5
         | 
| 49 53 |  | 
| 50 54 | 
             
              class << self
         | 
| 51 55 | 
             
                def run(*args, &block)
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: app_profiler
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.1. | 
| 4 | 
            +
              version: 0.1.4
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Gannon McGibbon
         | 
| @@ -13,7 +13,7 @@ authors: | |
| 13 13 | 
             
            autorequire: 
         | 
| 14 14 | 
             
            bindir: bin
         | 
| 15 15 | 
             
            cert_chain: []
         | 
| 16 | 
            -
            date:  | 
| 16 | 
            +
            date: 2023-09-20 00:00:00.000000000 Z
         | 
| 17 17 | 
             
            dependencies:
         | 
| 18 18 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 19 19 | 
             
              name: activesupport
         | 
| @@ -139,6 +139,7 @@ files: | |
| 139 139 | 
             
            - lib/app_profiler/middleware/base_action.rb
         | 
| 140 140 | 
             
            - lib/app_profiler/middleware/upload_action.rb
         | 
| 141 141 | 
             
            - lib/app_profiler/middleware/view_action.rb
         | 
| 142 | 
            +
            - lib/app_profiler/parameters.rb
         | 
| 142 143 | 
             
            - lib/app_profiler/profile.rb
         | 
| 143 144 | 
             
            - lib/app_profiler/profiler.rb
         | 
| 144 145 | 
             
            - lib/app_profiler/railtie.rb
         | 
| @@ -174,7 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 174 175 | 
             
                - !ruby/object:Gem::Version
         | 
| 175 176 | 
             
                  version: '0'
         | 
| 176 177 | 
             
            requirements: []
         | 
| 177 | 
            -
            rubygems_version: 3. | 
| 178 | 
            +
            rubygems_version: 3.4.19
         | 
| 178 179 | 
             
            signing_key: 
         | 
| 179 180 | 
             
            specification_version: 4
         | 
| 180 181 | 
             
            summary: Collect performance profiles for your Rails application.
         |