Class: Raygun::Apm::Sidekiq::Middleware

Inherits:
Object
  • Object
show all
Defined in:
lib/raygun/apm/sidekiq/middleware.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeMiddleware

Returns a new instance of Middleware.



5
6
7
# File 'lib/raygun/apm/sidekiq/middleware.rb', line 5

def initialize
  @tracer_initialized = nil
end

Class Method Details

.finalize(tracer) ⇒ Object



123
124
125
# File 'lib/raygun/apm/sidekiq/middleware.rb', line 123

def self.finalize(tracer)
  proc {tracer.process_ended}
end

Instance Method Details

#call(worker_instance, msg, queue) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/raygun/apm/sidekiq/middleware.rb', line 26

def call(worker_instance, msg, queue)
  @tracer_initialized ||= initialize_tracer
  # Can be nil if we had a fatal error
  if @tracer
    started = @tracer.now
    Thread.current.thread_variable_set(:_raygun_apm_tracer, @tracer)
    @tracer.start_trace
  end
  exception = nil
  Ruby_APM_profiler_trace do
    yield
  rescue => e
    exception = e
  end
  # Can be nil if we had a fatal error
  if @tracer
    fake_http_in_handler(started, worker_instance, msg, queue, exception)
    @tracer.end_trace
  end
rescue Raygun::Apm::FatalError => e
  raygun_shutdown_handler(e)
end

#fake_http_in_handler(started, worker_instance, msg, queue, exception) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/raygun/apm/sidekiq/middleware.rb', line 60

def fake_http_in_handler(started, worker_instance, msg, queue, exception)
  ended = @tracer.now
  event = http_in_event
  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)
  raise(exception) if exception
rescue => e
  warn "[Raygun APM] error reporting HTTP IN event"
  raygun_shutdown_handler(e)
end

#http_in_eventObject



75
76
77
78
79
80
81
82
# File 'lib/raygun/apm/sidekiq/middleware.rb', line 75

def http_in_event
  @http_in_event ||= begin
    event = Raygun::Apm::Event::HttpIn.new
    event[:pid] = Process.pid
    event[:verb] = "POST"
    event
  end
end

#initialize_tracerObject



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/raygun/apm/sidekiq/middleware.rb', line 9

def initialize_tracer
  @tracer = Raygun::Apm::Tracer.new
  @tracer.udp_sink!
  @tracer.process_started
  ObjectSpace.define_finalizer(self, self.class.finalize(@tracer))
  
  @sql_subscriber = ActiveSupport::Notifications.subscribe('sql.active_record') do |*args|
    sql_handler(args)
  end

  GC.stress = true if ENV['RAYGUN_STRESS_GC']

  # If any fatal errors on init, shutdown the tracer
rescue Raygun::Apm::FatalError => e
  raygun_shutdown_handler(e)
end

#raygun_shutdown_handler(exception) ⇒ Object



49
50
51
52
53
54
55
56
57
58
# File 'lib/raygun/apm/sidekiq/middleware.rb', line 49

def raygun_shutdown_handler(exception)
  warn "Raygun APM shutting down due to error - %s", exception.message
  # 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
  Thread.current.thread_variable_set(:_raygun_apm_tracer, nil)
  raise(exception) unless (Raygun::Apm::FatalError === exception)
end

#Ruby_APM_profiler_traceObject



119
120
121
# File 'lib/raygun/apm/sidekiq/middleware.rb', line 119

def Ruby_APM_profiler_trace
  yield
end

#sql_eventObject



111
112
113
114
115
116
117
# File 'lib/raygun/apm/sidekiq/middleware.rb', line 111

def sql_event
  @sql_event ||= begin
    event = Raygun::Apm::Event::Sql.new
    event[:pid] = Process.pid
    event
  end
end

#sql_handler(args) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/raygun/apm/sidekiq/middleware.rb', line 84

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[: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