class Rack::Profiler

Constants

DEFAULT_SUBSCRIPTIONS
VERSION

Attributes

authorizator[R]
backtrace_filter[R]
dashboard_path[RW]
events[R]
subscriptions[R]

Public Class Methods

new(app, &block) click to toggle source
# File lib/rack/profiler.rb, line 33
def initialize(app, &block)
  @events         = []
  @subscriptions  = []
  @dashboard_path = '/rack-profiler'
  @app            = app
  subscribe_to_default
  block.call(self) if block_given?

  if defined?(::Grape::Endpoint)
    ::Grape::Endpoint.include Rack::Grape::EndpointJson
  end
end
step(name, payload = {}) { || ... } click to toggle source
# File lib/rack/profiler.rb, line 27
def self.step(name, payload = {})
  ActiveSupport::Notifications.instrument('rack-profiler.step', payload.merge(step_name: name)) do
    yield
  end
end

Public Instance Methods

authorize(&block) click to toggle source
# File lib/rack/profiler.rb, line 83
def authorize(&block)
  @authorizator = block
end
call(env) click to toggle source
# File lib/rack/profiler.rb, line 46
def call(env)
  @events = []
  req = Rack::Request.new(env)
  env['rack-profiler'] = self

  if req.path == dashboard_path
    render_dashboard
  elsif req.params.has_key?('rack-profiler')
    render_profiler_results(env)
  else
    @app.call(env)
  end
end
filter_backtrace(&block) click to toggle source
# File lib/rack/profiler.rb, line 79
def filter_backtrace(&block)
  @backtrace_filter = block
end
subscribe(*events) click to toggle source
# File lib/rack/profiler.rb, line 60
def subscribe(*events)
  events.each do |event_name|
    next if @subscriptions.include?(event_name)
    ActiveSupport::Notifications.subscribe(event_name) do |name, start, finish, id, payload|
      evt = {
        id:        id,
        name:      name,
        start:     start.to_f,
        finish:    finish.to_f,
        duration:  (finish - start) * 1000,
        payload:   payload,
        backtrace: filtered_backtrace(caller(1))
      }
      (@events ||= []) << evt
    end
    @subscriptions << event_name
  end
end

Private Instance Methods

authorized?(env) click to toggle source
# File lib/rack/profiler.rb, line 138
def authorized?(env)
  @authorizator.nil? || @authorizator.call(env)
end
filtered_backtrace(backtrace) click to toggle source
# File lib/rack/profiler.rb, line 123
def filtered_backtrace(backtrace)
  if backtrace_filter.nil?
    backtrace
  else
    backtrace.select(&backtrace_filter)
  end
end
render_dashboard() click to toggle source
# File lib/rack/profiler.rb, line 110
def render_dashboard
  dashboard = ::File.expand_path( '../../public/rack-profiler.html',
                                 ::File.dirname( __FILE__ ) )
  body      = ::File.open(dashboard, ::File::RDONLY)
  [200, { 'Content-Type' => 'text/html' }, body]
end
render_profiler_results(env) click to toggle source
# File lib/rack/profiler.rb, line 89
def render_profiler_results(env)
  status, headers, body = [nil, nil, nil]
  ActiveSupport::Notifications.instrument('rack-profiler.total_time') do
    status, headers, body = @app.call(env)
  end
  return [status, headers, body] unless authorized?(env)
  # Grape will inject the env into the payload.
  # That'll cause problems with the json, so we'll just remove it.
  events.each { |e| e[:payload].delete(:env) }

  results = {
    events:   events.sort_by { |event| event[:start] },
    response: {
      status:  status,
      headers: headers,
      body:    stringify_body(body)
    }
  }
  [200, { 'Content-Type' => 'application/json' }, [results.to_json]]
end
stringify_body(body) click to toggle source
# File lib/rack/profiler.rb, line 131
def stringify_body(body)
  body.close if body.respond_to?(:close)
  str = ""
  body.each { |part| str << part }
  str
end
subscribe_to_default() click to toggle source
# File lib/rack/profiler.rb, line 117
def subscribe_to_default
  DEFAULT_SUBSCRIPTIONS.each do |event|
    subscribe(event)
  end
end