Class: NewRelic::Agent::Instrumentation::ActiveJobSubscriber

Inherits:
NotificationsSubscriber show all
Defined in:
lib/new_relic/agent/instrumentation/active_job_subscriber.rb

Constant Summary collapse

PAYLOAD_KEYS =
%i[adapter db_runtime error job wait jobs step interrupted]
PATTERN =
/\A([^\.]+)\.active_job\z/
METHOD_NAME_MAPPING =
Hash.new do |h, k|
  if PATTERN =~ k
    h[k] = $1
  else
    h[k] = NewRelic::UNKNOWN
  end
end

Instance Method Summary collapse

Methods inherited from NotificationsSubscriber

#define_exception_method, find_all_subscribers, #finish, #initialize, #log_notification_error, #pop_segment, #push_segment, #segment_stack, #start, #state, subscribe, subscribed?

Constructor Details

This class inherits a constructor from NewRelic::Agent::Instrumentation::NotificationsSubscriber

Instance Method Details

#add_segment_params(segment, payload) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/new_relic/agent/instrumentation/active_job_subscriber.rb', line 27

def add_segment_params(segment, payload)
  PAYLOAD_KEYS.each do |key|
    segment.params[key] = payload[key] if payload.key?(key)
  end

  # Add step name for Rails 8.1+ Continuations (available at start)
  if payload[:step]&.respond_to?(:name)
    step = payload[:step]
    segment.params[:step_name] = step.name.to_s
    segment.params[:resumed] = step.resumed if step.respond_to?(:resumed)
  end
end

#finish_segment(id, payload) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/new_relic/agent/instrumentation/active_job_subscriber.rb', line 40

def finish_segment(id, payload)
  segment = pop_segment(id)
  return unless segment

  # Update step-specific attributes that are only available after step execution
  if payload[:step]&.respond_to?(:cursor)
    step = payload[:step]
    segment.params[:cursor] = step.cursor if step.cursor
  end

  if exception = exception_object(payload)
    segment.notice_error(exception)
  end
  segment.finish
end

#method_from_name(name) ⇒ Object



86
87
88
# File 'lib/new_relic/agent/instrumentation/active_job_subscriber.rb', line 86

def method_from_name(name)
  METHOD_NAME_MAPPING[name]
end

#metric_name(name, payload) ⇒ Object

NOTE: For enqueue_all.active_job, only the first job is used to determine the queue. Therefore, this assumes all jobs given as arguments for perform_all_later share the same queue.



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/new_relic/agent/instrumentation/active_job_subscriber.rb', line 58

def metric_name(name, payload)
  job = payload[:job] || payload[:jobs].first

  queue = job.queue_name
  job_class = job.class.name.include?('::') ? job.class.name[job.class.name.rindex('::') + 2..-1] : job.class.name
  method = method_from_name(name)

  # Include step name for Rails 8.1+ Continuations (unless disabled via config)
  if (method == 'step' || method == 'step_started') &&
      payload[:step]&.respond_to?(:name) &&
      !NewRelic::Agent.config[:disable_active_job_step_names]
    step_name = payload[:step].name
    "Ruby/ActiveJob/#{queue}/#{job_class}/#{method}/#{step_name}"
  else
    "Ruby/ActiveJob/#{queue}/#{job_class}/#{method}"
  end
end

#span_kind_for(name) ⇒ Object



20
21
22
23
24
25
# File 'lib/new_relic/agent/instrumentation/active_job_subscriber.rb', line 20

def span_kind_for(name)
  case method_from_name(name)
  when /\Aenqueue/ then ::NewRelic::Agent::SpanEventPrimitive::PRODUCER
  when /\Aperform/ then ::NewRelic::Agent::SpanEventPrimitive::CONSUMER
  end
end

#start_segment(name, id, payload) ⇒ Object



13
14
15
16
17
18
# File 'lib/new_relic/agent/instrumentation/active_job_subscriber.rb', line 13

def start_segment(name, id, payload)
  segment = Tracer.start_segment(name: metric_name(name, payload))
  segment.span_kind = span_kind_for(name)
  add_segment_params(segment, payload)
  push_segment(id, segment)
end