Skip to content

Commit

Permalink
Instrument middleware processing
Browse files Browse the repository at this point in the history
Adds ActiveSupport::Notifications instrumentation of the processing of
each middleware in the stack.
  • Loading branch information
dasch authored and jeremy committed Mar 19, 2019
1 parent 299573a commit 04ae0b0
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 7 deletions.
23 changes: 22 additions & 1 deletion actionpack/lib/action_dispatch/middleware/stack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,28 @@ def inspect
end

def build(app)
klass.new(app, *args, &block)
InstrumentationProxy.new(klass.new(app, *args, &block), inspect)
end
end

# This class is used to instrument the execution of a single middleware.
# It proxies the `call` method transparently and instruments the method
# call.
class InstrumentationProxy
EVENT_NAME = "process_middleware.action_dispatch"

def initialize(middleware, class_name)
@middleware = middleware

@payload = {
middleware: class_name,
}
end

def call(env)
ActiveSupport::Notifications.instrument(EVENT_NAME, @payload) do
@middleware.call(env)
end
end
end

Expand Down
41 changes: 35 additions & 6 deletions actionpack/test/dispatch/middleware_stack_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,24 @@
require "abstract_unit"

class MiddlewareStackTest < ActiveSupport::TestCase
class FooMiddleware; end
class BarMiddleware; end
class BazMiddleware; end
class HiyaMiddleware; end
class BlockMiddleware
class Base
def initialize(app)
@app = app
end

def call(env)
@app.call(env)
end
end

class FooMiddleware < Base; end
class BarMiddleware < Base; end
class BazMiddleware < Base; end
class HiyaMiddleware < Base; end
class BlockMiddleware < Base
attr_reader :block
def initialize(&block)
def initialize(app, &block)
super(app)
@block = block
end
end
Expand Down Expand Up @@ -109,6 +120,24 @@ def test_delete_works
assert_equal @stack.last, @stack.last
end

test "instruments the execution of middlewares" do
app = @stack.build(proc { |env| [200, {}, []] })
env = {}

events = []

subscriber = proc do |*args|
events << ActiveSupport::Notifications::Event.new(*args)
end

ActiveSupport::Notifications.subscribed(subscriber, "process_middleware.action_dispatch") do
app.call(env)
end

assert_equal 2, events.count
assert_equal ["MiddlewareStackTest::BarMiddleware", "MiddlewareStackTest::FooMiddleware"], events.map { |e| e.payload[:middleware] }
end

test "includes a middleware" do
assert_equal true, @stack.include?(ActionDispatch::MiddlewareStack::Middleware.new(BarMiddleware, nil, nil))
end
Expand Down

0 comments on commit 04ae0b0

Please sign in to comment.