Skip to content

Instantly share code, notes, and snippets.

Last active April 4, 2017 13:20
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?
Small rack server timing middleware
# This simple Rack middleware subscribes to all AS::Notifications
# and adds the appropriate `Server-Timing` header as described in
# the spec [1] with the notifications grouped by name and with the
# elapsed time added up.
# [1] Server Timing spec:
module Rack
class ServerTimingMiddleware
def initialize(app)
@app = app
def call(env)
events = []
subs = ActiveSupport::Notifications.subscribe(//) do |*args|
events <<*args)
status, headers, body =
# As the doc states, this harms the internal AS:Notifications
# caches, but I'd say it's necessary so we don't leak memory
mapped_events = events.group_by { |el|
}.map{ |event_name, event_data|
agg_time ={ |ev|
}.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=0.009; "CPU", mysql=0.005; "MySQL", filesystem=0.006; "Filesystem"'
headers['Server-Timing'] = do |name, elapsed_time|
"#{name}=#{elapsed_time}; \"#{name}\""
end.join(', ')
[status, headers, body]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment