class Raygun::Apm::Rails::Middleware
Constants
- POSTGRESQLSTRING
Public Class Methods
new(app)
click to toggle source
# File lib/raygun/apm/rails/middleware.rb, line 6 def initialize(app) @app = app @mutex = Mutex.new @tracer = nil end
Private Class Methods
finalize(tracer)
click to toggle source
# File lib/raygun/apm/rails/middleware.rb, line 200 def self.finalize(tracer) proc {tracer.process_ended} end
Public Instance Methods
call(env)
click to toggle source
# File lib/raygun/apm/rails/middleware.rb, line 12 def call(env) @status, @headers, @response = instrument(env) [@status, @headers, @response] end
Private Instance Methods
Ruby_APM_profiler_trace() { || ... }
click to toggle source
# File lib/raygun/apm/rails/middleware.rb, line 185 def Ruby_APM_profiler_trace yield end
Ruby_APM_request_error() { || ... }
click to toggle source
# File lib/raygun/apm/rails/middleware.rb, line 189 def Ruby_APM_request_error yield end
crash_report_exception(exception, env = {})
click to toggle source
# File lib/raygun/apm/rails/middleware.rb, line 193 def crash_report_exception(exception, env = {}) if Raygun::Apm::Rails.raygun4ruby? env.merge!(correlation_id: exception.instance_variable_get(:@__raygun_correlation_id)) Raygun.track_exception(exception, env) end end
exceptional_http_in_handler(env)
click to toggle source
For middleware chain halts that does not trigger 'process_action.action_controller'
# File lib/raygun/apm/rails/middleware.rb, line 125 def exceptional_http_in_handler(env) req = Rack::Request.new env event = http_in_event event[:pid] = Process.pid event[:url] = req.url event[:verb] = req.request_method event[:status] = 500 event[:duration] = @tracer.now - @request_started event[:timestamp] = @tracer.now event[:tid] = @tracer.get_thread_id(Thread.current) @tracer.emit(event) rescue => e warn "[Raygun APM] error reporting exceptional HTTP IN event" raygun_shutdown_handler(e) end
get_sql_provider_name(config)
click to toggle source
This function adjusts the provider name for PostgreSQL to Postgres because all other Raygun
profilers use Postgres and this will keep the UI consistent across supported languages
# File lib/raygun/apm/rails/middleware.rb, line 174 def get_sql_provider_name(config) if config[:adapter] == POSTGRESQLSTRING return "postgres" end config[:adapter] end
http_in_event()
click to toggle source
# File lib/raygun/apm/rails/middleware.rb, line 141 def http_in_event @http_in_event ||= Raygun::Apm::Event::HttpIn.new end
http_in_handler(args)
click to toggle source
# File lib/raygun/apm/rails/middleware.rb, line 89 def http_in_handler(args) notification = ActiveSupport::Notifications::Event.new *args if notification.payload[:exception] return end if headers = notification.payload[:headers] req = Rack::Request.new headers.env url = req.url verb = req.request_method else url = notification.payload[:path] verb = notification.payload[:method].to_s.upcase end event = http_in_event event[:pid] = Process.pid event[:url] = url event[:verb] = verb event[:status] = http_in_status(notification) # XXX constant milliseconds to microseconds event[:duration] = notification.duration * 1000 event[:timestamp] = @tracer.now event[:tid] = @tracer.get_thread_id(Thread.current) @tracer.emit(event) rescue => e warn "[Raygun APM] error reporting HTTP IN event" raygun_shutdown_handler(e) end
http_in_status(notification)
click to toggle source
# File lib/raygun/apm/rails/middleware.rb, line 117 def http_in_status(notification) notification.payload[:status] || notification.payload[:headers]["action_controller.instance"].status rescue warn "[Raygun APM] error inferring HTTP status, fallback to 200" 200 end
init_tracer()
click to toggle source
# File lib/raygun/apm/rails/middleware.rb, line 55 def init_tracer tracer = Raygun::Apm::Tracer.new tracer.udp_sink! ObjectSpace.define_finalizer(self, self.class.finalize(tracer)) ActiveSupport::Notifications.unsubscribe(@http_in_subscriber) if @http_in_subscriber @http_in_subscriber = ActiveSupport::Notifications.subscribe('process_action.action_controller') do |*args| http_in_handler(args) if @tracer end ActiveSupport::Notifications.unsubscribe(@sql_subscriber) if @sql_subscriber @sql_subscriber = ActiveSupport::Notifications.subscribe('sql.active_record') do |*args| sql_handler(args) if @tracer end GC.stress = true if ENV['RAYGUN_STRESS_GC'] Raygun::Apm::Tracer.instance = tracer # If any fatal errors on init, shutdown the tracer rescue Raygun::Apm::FatalError => e raygun_shutdown_handler(e) end
instrument(env)
click to toggle source
# File lib/raygun/apm/rails/middleware.rb, line 19 def instrument(env) # Ignore asset requests if (env['REQUEST_PATH'] || env['REQUEST_URI']).match(/^\/assets\//) return @app.call(env) end @mutex.synchronize do # Can be nil if we had a fatal error @tracer = Raygun::Apm::Tracer.instance || init_tracer end if @tracer # For the exceptional HTTP IN handler @request_started = @tracer.now @tracer.start_trace end exception = nil res = nil Ruby_APM_profiler_trace do begin res = @app.call(env) rescue => e crash_report_exception(e, env) exceptional_http_in_handler(env) if @tracer exception = e end end # Can be nil if we had a fatal error if @tracer @tracer.diagnostics if ENV['PROTON_DIAGNOSTICS'] @tracer.end_trace end raise exception if exception res rescue Raygun::Apm::FatalError => e raygun_shutdown_handler(e) end
raygun_shutdown_handler(exception)
click to toggle source
# File lib/raygun/apm/rails/middleware.rb, line 77 def raygun_shutdown_handler(exception) warn "[Raygun APM] shutting down due to error - #{exception.message} #{exception.backtrace.join("\n")}", # Kill extended event subcriptions ActiveSupport::Notifications.unsubscribe(@http_in_subscriber) ActiveSupport::Notifications.unsubscribe(@sql_subscriber) warn "[Raygun APM] notification hooks unsubscribed" @tracer.end_trace # Let the GC clean up the sink thread through the finalizer below @tracer = Raygun::Apm::Tracer.instance = nil raise(exception) unless (Raygun::Apm::FatalError === exception) end
sql_event()
click to toggle source
# File lib/raygun/apm/rails/middleware.rb, line 181 def sql_event @sql_event ||= Raygun::Apm::Event::Sql.new end
sql_handler(args)
click to toggle source
# File lib/raygun/apm/rails/middleware.rb, line 145 def sql_handler(args) notification = ActiveSupport::Notifications::Event.new *args connection = if notification.payload[:connection] notification.payload[:connection] else ObjectSpace._id2ref(notification.payload[:connection_id]) end event = sql_event event[:pid] = Process.pid event[:query] = notification.payload[:sql] # XXX this is hacky if config = connection.instance_variable_get('@config') event[:provider] = get_sql_provider_name(config) event[:host] = config[:host] event[:database] = config[:database] end # XXX constant milliseconds to microseconds event[:duration] = notification.duration * 1000 event[:timestamp] = notification.time.to_f * 1000000 event[:tid] = @tracer.get_thread_id(Thread.current) @tracer.emit(event) rescue => e warn "[Raygun APM] error reporting SQL event" raygun_shutdown_handler(e) end