module Raygun::Apm::Sidekiq::Hook

Public Class Methods

finalize(tracer) click to toggle source
# File lib/raygun/apm/sidekiq/hook.rb, line 8
def self.finalize(tracer)
  proc {tracer.process_ended}
end
new(*args) click to toggle source
Calls superclass method
# File lib/raygun/apm/sidekiq/hook.rb, line 12
def initialize(*args)
  super
  @mutex = Mutex.new
  @mutex.synchronize do
    @tracer = Raygun::Apm::Tracer.instance || init_tracer          
  end
end

Public Instance Methods

process(work) click to toggle source
Calls superclass method
# File lib/raygun/apm/sidekiq/hook.rb, line 20
def process(work)
  job_hash = ::Sidekiq.load_json(work.job)
  queue = work.queue_name
  # Can be nil if we had a fatal error
  if @tracer
     @worker_started = @tracer.now
     @tracer.start_trace
  end
  exception = nil
  Ruby_APM_profiler_trace do
    begin
      super
      fake_http_in_handler(@tracer, @worker_started, job_hash, queue, nil) if @tracer
    rescue => e
      fake_http_in_handler(@tracer, @worker_started, job_hash, queue, e) 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
rescue Raygun::Apm::FatalError => e
  raygun_shutdown_handler(e)
end

Private Instance Methods

Ruby_APM_profiler_trace() { || ... } click to toggle source
# File lib/raygun/apm/sidekiq/hook.rb, line 133
def Ruby_APM_profiler_trace
  yield
end
fake_http_in_handler(tracer, started, msg, queue, exception) click to toggle source
# File lib/raygun/apm/sidekiq/hook.rb, line 78
def fake_http_in_handler(tracer, started, msg, queue, exception)
  ended = tracer.now
  event = http_in_event
  event[:pid] = Process.pid
  event[:url] = "sidekiq://#{queue}/#{msg["class"]}?#{msg["jid"]}"
  event[:status] = exception ? 500 : 200
  event[:duration] = ended - started
  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 #{e.class} #{e.backtrace.join("\n")}"
  raygun_shutdown_handler(e)
end
http_in_event() click to toggle source
# File lib/raygun/apm/sidekiq/hook.rb, line 93
def http_in_event
  @http_in_event ||= begin
    event = Raygun::Apm::Event::HttpIn.new
    event[:verb] = "POST"
    event
  end
end
init_tracer() click to toggle source
# File lib/raygun/apm/sidekiq/hook.rb, line 50
def init_tracer
  tracer = Raygun::Apm::Tracer.new
  tracer.udp_sink!
  ObjectSpace.define_finalizer(self, Hook.finalize(tracer))

  ActiveSupport::Notifications.unsubscribe(@sql_subscriber) if @sql_subscriber
  @sql_subscriber = ActiveSupport::Notifications.subscribe('sql.active_record') do |*args|
    sql_handler(tracer, args)
  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
raygun_shutdown_handler(exception) click to toggle source
# File lib/raygun/apm/sidekiq/hook.rb, line 67
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(@sql_subscriber)
  warn "[Raygun APM] notification hooks unsubscribed"
  # Let the GC clean up the sink thread through the finalizer below
  @tracer = nil
  Raygun::Apm::Tracer.instance = nil
  raise(exception) unless (Raygun::Apm::FatalError === exception)
end
sql_event() click to toggle source
# File lib/raygun/apm/sidekiq/hook.rb, line 129
def sql_event
  @sql_event ||= Raygun::Apm::Event::Sql.new
end
sql_handler(tracer, args) click to toggle source
# File lib/raygun/apm/sidekiq/hook.rb, line 101
def sql_handler(tracer, 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] = config[:adapter]
    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