require 'benchmark' module Logworm class Rack def initialize(app, options = {}) @app = app @log_requests_short = options[:log_requests].nil? or options[:log_requests] != false @log_requests_long = !options[:log_requests_long].nil? and options[:log_requests_long] == true end def call(env) return @app.call(env) unless ENV['RACK_ENV'] == 'production' startTime = Time.now Logger.start_cycle status, headers, body = @app.call(env) appTime = (Time.now - startTime) Logger.log(:web_log_long, {:summary => "#{env['REQUEST_METHOD']} #{env['REQUEST_URI']} - #{status} #{appTime}", :request => env_to_log(env), :response => {:status => status, :headers => headers}, :profiling => appTime}) if @log_requests_long Logger.log(:web_log, {:summary => "#{env['REQUEST_METHOD']} #{env['REQUEST_URI']} - #{status} #{appTime}", :request_path => env['REQUEST_PATH'], :request_ip => env['REMOTE_ADDR'], :request_method => env['REQUEST_METHOD'], :input => collect_input(env), :response_status => status, :profiling => appTime, :queue_size => env['HTTP_X_HEROKU_QUEUE_DEPTH'] || '-1'}) if @log_requests_short begin Timeout::timeout(1) { sent = 0 ts = Benchmark.realtime {sent = Logger.flush} # Flushes only if there are any entries. Times out after a second env['rack.errors'].puts("\t *** logworm - logs sent in #{ts} seconds") if sent > 0 } rescue Exception => e # Ignore --nothing we can do # The list of logs may (and most likely will) be preserved for the next request env['rack.errors'].puts "logworm call failed: #{e}" end [status, headers, body] end private def env_to_log(env) to_log = {} env.each do |k,v| to_log[k.to_s.downcase.to_sym] = v unless (k.to_s =~ /rack/i or k.to_s =~ /\./i) end to_log.merge({:input => collect_input(env)}) end def collect_input(env) inputstr = "" env['rack.input'].each {|content| inputstr += content } env['rack.input'].rewind inputstr end end end