Skip to content

Dev Trace middleware doesn't adjust_html if Hotwire::Spark is in middleware #562

@benngarcia

Description

@benngarcia

There is an issue with the ScoutApm::Instant::Middleware

Currently, it tries to detect development assets via:

logger.debug("DevTrace: dev asset ignored") and return false if development_asset?

  logger.debug("DevTrace: dev asset ignored") and return false if development_asset?

...
  def development_asset?
    !rack_body.respond_to?(:body)
  end

which seems to be aligned with how newer_rails_response? and rack_proxy_response? try to detect an application response (instead of a response from something like the ActionDispatch::Static middleware)

  def newer_rails_response?
    if defined?(ActionDispatch::Response::RackBody)
      return true if rack_body.is_a?(ActionDispatch::Response::RackBody)
    end
  end

  def rack_proxy_response?
    rack_body.is_a?(::Rack::BodyProxy)
  end

This causes issues with the Hotwire::Spark middleware: https://github.com/hotwired/spark/blob/main/lib/hotwire/spark/middleware.rb
which also modifies the response, but doesn't wrap the Rack body back-up with the ActionDispatch::Response::RackBody that it received.

You can see it takes the response (standard body or a stream), collects it all, modifies the HTML, and then returns an array instead of the original class it received (which would respond_to(:body)). This means that ScoutAPM is interpreting this as a development asset, and discarding it.

While I think the onus is more on Hotwire::Spark to "Leave no trace", I'm raising this issue here for visibility in case others come across the same issue
( I was able to fix with the following addition to config/environments/development.rb):

if defined?(Hotwire::Spark::Middleware) && defined?(ScoutApm::Instant::Middleware) && Hotwire::Spark.enabled?
  config.middleware.move_after(Hotwire::Spark::Middleware, ScoutApm::Instant::Middleware)
end

But also I do think ScoutAPM could be more resilient with its development asset detection. I.e., looking at how Propshaft and/or Sprockets do it.

https://github.com/rails/propshaft/blob/main/lib/propshaft/quiet_assets.rb
https://github.com/rails/sprockets-rails/blob/master/lib/sprockets/rails/quiet_assets.rb

Happy to help with implementation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions