class Rack::ServerTimingMiddleware

Public Class Methods

new(app) click to toggle source
# File lib/server_timing_middleware.rb, line 10
def initialize(app)
  @app = app
end

Public Instance Methods

call(env) click to toggle source
# File lib/server_timing_middleware.rb, line 13
def call(env)

  events = []

  subs = ActiveSupport::Notifications.subscribe(//) do |*args|
    events << ActiveSupport::Notifications::Event.new(*args)
  end

  status, headers, body = @app.call(env)

  # As the doc states, this harms the internal AS:Notifications
  # caches, but I'd say it's necessary so we don't leak memory
  ActiveSupport::Notifications.unsubscribe(subs)

  mapped_events = events.group_by { |el|
    el.name
  }.map{ |event_name, event_data|
    agg_time = event_data.map{ |ev|
      ev.duration
    }.inject(0){ |curr, accum| curr += accum}

    # We need the string formatter as the scientific notation
    # a.k.a <number>e[+-]<exponent> is not allowed

    # Time divided by 1000 as it's in milliseconds
    [event_name, '%.10f' % (agg_time/1000)]
  }

  # Example output:
  #   'cpu;dur=0.009;desc="CPU", mysql;dur=0.005;desc="MySQL", filesystem;dur=0.006;desc="Filesystem"'
  headers['Server-Timing'] = mapped_events.map do |name, elapsed_time|
    "#{name};dur=#{elapsed_time};desc=\"#{name}\""
  end.join(',')

  [status, headers, body]
end