1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
|
# frozen_string_literal: true
# :markup: markdown
require "active_support/notifications"
module ActionDispatch
class ServerTiming
class Subscriber # :nodoc:
include Singleton
KEY = :action_dispatch_server_timing_events
def initialize
@mutex = Mutex.new
end
def call(event)
if events = ActiveSupport::IsolatedExecutionState[KEY]
events << event
end
end
def collect_events
events = []
ActiveSupport::IsolatedExecutionState[KEY] = events
yield
events
ensure
ActiveSupport::IsolatedExecutionState.delete(KEY)
end
def ensure_subscribed
@mutex.synchronize do
# Subscribe to all events, except those beginning with "!" Ideally we would be
# more selective of what is being measured
@subscriber ||= ActiveSupport::Notifications.subscribe(/\A[^!]/, self)
end
end
def unsubscribe
@mutex.synchronize do
ActiveSupport::Notifications.unsubscribe @subscriber
@subscriber = nil
end
end
end
def self.unsubscribe # :nodoc:
Subscriber.instance.unsubscribe
end
def initialize(app)
@app = app
@subscriber = Subscriber.instance
@subscriber.ensure_subscribed
end
def call(env)
response = nil
events = @subscriber.collect_events do
response = @app.call(env)
end
headers = response[1]
header_info = events.group_by(&:name).map do |event_name, events_collection|
"%s;dur=%.2f" % [event_name, events_collection.sum(&:duration)]
end
if headers[ActionDispatch::Constants::SERVER_TIMING].present?
header_info.prepend(headers[ActionDispatch::Constants::SERVER_TIMING])
end
headers[ActionDispatch::Constants::SERVER_TIMING] = header_info.join(", ")
response
end
end
end
|