|  | class ApplicationController < ActionController::Base | 
        
          |  |  | 
        
          |  | rescue_from Exception, :with => :handle_exception | 
        
          |  | rescue_from ActiveRecord::RecordNotFound, :with => :handle_not_found | 
        
          |  |  | 
        
          |  | before_filter :setup_logging | 
        
          |  |  | 
        
          |  |  | 
        
          |  | # [...] | 
        
          |  |  | 
        
          |  |  | 
        
          |  | private | 
        
          |  |  | 
        
          |  | def redirect_to(*a, &b) | 
        
          |  | #Set previous-request-id to track redirects | 
        
          |  | flash['previous-request-id'] = request.uuid | 
        
          |  | super(*a, &b) | 
        
          |  | end | 
        
          |  |  | 
        
          |  |  | 
        
          |  | def emit_event(atts) | 
        
          |  | atts['data'] ||= {} | 
        
          |  | atts['data']['http'] ||= {} | 
        
          |  | atts['data']['http']['request-id'] ||= request.uuid | 
        
          |  | $ZMQ_LOGGER.emit(atts) | 
        
          |  | rescue Exception => e | 
        
          |  | logger.error "[LOGGING ERROR] #{e.class}: #{e.message}\n#{e.backtrace.map{|l|  "  #{l}"}.join("\n")}" | 
        
          |  | end | 
        
          |  |  | 
        
          |  | def log_message(atts) | 
        
          |  | atts['data'] ||= {} | 
        
          |  | atts['data']['http'] ||= {} | 
        
          |  | atts['data']['http']['request-id'] ||= request.uuid | 
        
          |  | $ZMQ_LOGGER.log(atts) | 
        
          |  | rescue Exception => e | 
        
          |  | logger.error "[LOGGING ERROR] #{e.class}: #{e.message}\n#{e.backtrace.map{|l|  "  #{l}"}.join("\n")}" | 
        
          |  | end | 
        
          |  |  | 
        
          |  |  | 
        
          |  | def memory_usage#in kB | 
        
          |  | `ps -o rss= -p #{Process.pid}`.strip.to_i | 
        
          |  | rescue | 
        
          |  | nil | 
        
          |  | end | 
        
          |  |  | 
        
          |  |  | 
        
          |  | def handle_not_found(exception) | 
        
          |  | log_exception(exception) | 
        
          |  |  | 
        
          |  | if true#Rails.env.production? | 
        
          |  | respond_to do |format| | 
        
          |  | format.html{ render file: Rails.root.join('public', '404.html'), layout: false, status: 404 } | 
        
          |  | format.xml{ render xml: error_xml('The requested resource could not be found'), status: 404 } | 
        
          |  | end | 
        
          |  | else | 
        
          |  | raise exception | 
        
          |  | end | 
        
          |  | rescue Exception => e | 
        
          |  | logger.error "[EXCEPTION LOGGING EXCEPTION] #{e.class}: #{e.message}\n#{e.backtrace.map{|l|  "  #{l}"}.join("\n")}" | 
        
          |  | render :text => "Inxception :(" | 
        
          |  | end | 
        
          |  |  | 
        
          |  |  | 
        
          |  | def handle_exception(exception) | 
        
          |  | if Rails.env.development? | 
        
          |  | log_exception(exception) | 
        
          |  | raise exception | 
        
          |  | else | 
        
          |  | begin | 
        
          |  | log_exception(exception) | 
        
          |  | respond_to do |format| | 
        
          |  | format.html{ render file: Rails.root.join('public', '500.html'), layout: false, status: 500 } | 
        
          |  | end | 
        
          |  | rescue Exception => e | 
        
          |  | logger.error "[EXCEPTION LOGGING EXCEPTION] #{e.class}: #{e.message}\n#{e.backtrace.map{|l|  "  #{l}"}.join("\n")}" | 
        
          |  | render :text => "Inxception :(", status: 500 | 
        
          |  | end | 
        
          |  | end | 
        
          |  | end | 
        
          |  |  | 
        
          |  |  | 
        
          |  | def log_exception(exception) | 
        
          |  | atts = { | 
        
          |  | 'type' => 'exception', | 
        
          |  | 'message' => 'Uncaught exception', | 
        
          |  | 'description' => 'An unanticipated exception occured', | 
        
          |  | 'data' => { | 
        
          |  | 'exception' => { | 
        
          |  | 'type' => exception.class.name, | 
        
          |  | 'message' => exception.message, | 
        
          |  | 'backtrace' => exception.backtrace | 
        
          |  | }, | 
        
          |  | 'http' => request_data_for_logging | 
        
          |  | } | 
        
          |  | } | 
        
          |  |  | 
        
          |  | log_message(atts) | 
        
          |  | end | 
        
          |  |  | 
        
          |  |  | 
        
          |  | def setup_logging | 
        
          |  | @memory_before = memory_usage | 
        
          |  | start = Time.now | 
        
          |  | instr, mw = nil, nil | 
        
          |  | ActiveSupport::Notifications.instrument('zmq-logger.call-me', ->(atts){ | 
        
          |  | instr = atts | 
        
          |  | log_request(atts, mw) if mw | 
        
          |  | }) | 
        
          |  | request.env['zmq-logger.get-data'].call(->(data){ | 
        
          |  | mw = data | 
        
          |  | log_request(instr, data) if instr | 
        
          |  | }) | 
        
          |  | end | 
        
          |  |  | 
        
          |  |  | 
        
          |  | def log_request(instr, mw) | 
        
          |  | atts = { | 
        
          |  | 'type' => 'request', | 
        
          |  | 'data' => { | 
        
          |  | 'time' => mw['rack_stop']-mw['rack_start'], | 
        
          |  | 'timing' => { | 
        
          |  | 'rails_start' => instr['start'], | 
        
          |  | 'rails_stop' => instr['stop'], | 
        
          |  | 'rails_time' => instr['stop']-instr['start'], | 
        
          |  | 'rack_start' => mw['rack_start'], | 
        
          |  | 'rack_stop' => mw['rack_stop'], | 
        
          |  | 'rack_time' => mw['rack_stop']-mw['rack_start'], | 
        
          |  | 'rails_db_time' => instr['db_runtime'], | 
        
          |  | 'rails_view_time' => instr['view_runtime'], | 
        
          |  | 'custom' => timing_data_for_logging | 
        
          |  | }, | 
        
          |  | 'memory' => [@memory_before, memory_usage], #[start of request, end of request] | 
        
          |  | 'queries' => instr['queries'], | 
        
          |  | 'renders' => instr['renders'], | 
        
          |  | 'user' => { | 
        
          |  | 'id' => current_user && current_user.id, | 
        
          |  | 'username' => current_user && current_user.username | 
        
          |  | }, | 
        
          |  | 'http' => request_data_for_logging.merge( | 
        
          |  | 'response' => { | 
        
          |  | 'status' => mw['status'], | 
        
          |  | 'headers' => mw['headers'], | 
        
          |  | 'body' => false && mw['body'] # You may not want to log every response body | 
        
          |  | } | 
        
          |  | ) | 
        
          |  | } | 
        
          |  | } | 
        
          |  |  | 
        
          |  | if mw['request_start'] | 
        
          |  | atts['data']['timing'].merge!( | 
        
          |  | 'request_start' => mw['request_start'], | 
        
          |  | 'request_time' => atts['data']['timing']['rack_stop'] - mw['request_start'], | 
        
          |  | 'queue_time' => atts['data']['timing']['rack_start'] - mw['request_start'] | 
        
          |  | ) | 
        
          |  | end | 
        
          |  |  | 
        
          |  | log_message(atts) | 
        
          |  | end | 
        
          |  |  | 
        
          |  |  | 
        
          |  | def request_data_for_logging | 
        
          |  | atts = { | 
        
          |  | 'request-id' => request.uuid, | 
        
          |  | 'headers' => request_headers_for_logging, | 
        
          |  | 'method' => request.method, | 
        
          |  | 'params' => request.filtered_parameters, | 
        
          |  | 'session' => session | 
        
          |  | } | 
        
          |  |  | 
        
          |  | #If this was the result of a redirect, see if previous request left its ID so we can tie them together | 
        
          |  | atts['referer-request-id'] = flash['previous-request-id'] if flash['previous-request-id'] && flash['previous-request-id'] != atts['request-id'] | 
        
          |  |  | 
        
          |  | atts | 
        
          |  | end | 
        
          |  |  | 
        
          |  |  | 
        
          |  | #Scrub headers for logging. headers == rack env, which has lots of crap in it from middleware | 
        
          |  | def request_headers_for_logging | 
        
          |  | headers = request.headers.reject do |key, value| | 
        
          |  | (!key.is_a?(String) && !key.is_a?(Symbol)) || !value.is_a?(String) || | 
        
          |  | key.to_s =~ /\A(rack|action_controller|action_dispatch|zmq-logger)/ || | 
        
          |  | key == 'HTTP_COOKIE' | 
        
          |  | end | 
        
          |  | #headers['HTTP_X_API_KEY'] = '[FILTERED]' if headers['HTTP_X_API_KEY'] | 
        
          |  | headers | 
        
          |  | end | 
        
          |  |  | 
        
          |  |  | 
        
          |  | def timing_data_for_logging | 
        
          |  | @timing_data_for_logging ||= Hash.new{|h,k| h[k] = [] } | 
        
          |  | end | 
        
          |  |  | 
        
          |  | def time(name, &block) | 
        
          |  | t = Time.now | 
        
          |  | r = yield | 
        
          |  | timing_data_for_logging[name] << Time.now-t | 
        
          |  | r | 
        
          |  | end | 
        
          |  | helper_method :time | 
        
          |  |  | 
        
          |  |  | 
        
          |  | end |