Class: NewRelic::Agent::Instrumentation::MetricFrame

Inherits:
Object
  • Object
show all
Defined in:
lib/new_relic/agent/instrumentation/metric_frame.rb

Overview

A struct holding the information required to measure a controller action. This is put on the thread local. Handles the issue of re-entrancy, or nested action calls.

This class is not part of the public API. Avoid making calls on it directly.

Constant Summary collapse

@@java_classes_loaded =
false

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeMetricFrame

Returns a new instance of MetricFrame.



38
39
40
41
42
43
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 38

def initialize
  @start = Time.now.to_f
  @path_stack = [] # stack of [controller, path] elements
  @jruby_cpu_start = jruby_cpu_time
  @process_cpu_start = process_cpu
end

Instance Attribute Details

#apdex_startObject

Returns the value of attribute apdex_start.



8
9
10
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 8

def apdex_start
  @apdex_start
end

#available_requestObject

Returns the value of attribute available_request.



8
9
10
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 8

def available_request
  @available_request
end

#database_metric_nameObject

Returns the value of attribute database_metric_name.



8
9
10
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 8

def database_metric_name
  @database_metric_name
end

#depthObject (readonly)

Returns the value of attribute depth.



36
37
38
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 36

def depth
  @depth
end

#exceptionObject

Returns the value of attribute exception.



8
9
10
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 8

def exception
  @exception
end

#filtered_paramsObject

Returns the value of attribute filtered_params.



8
9
10
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 8

def filtered_params
  @filtered_params
end

#force_flagObject

Returns the value of attribute force_flag.



8
9
10
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 8

def force_flag
  @force_flag
end

#jruby_cpu_startObject

Returns the value of attribute jruby_cpu_start.



8
9
10
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 8

def jruby_cpu_start
  @jruby_cpu_start
end

#process_cpu_startObject

Returns the value of attribute process_cpu_start.



8
9
10
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 8

def process_cpu_start
  @process_cpu_start
end

#startObject

Returns the value of attribute start.



8
9
10
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 8

def start
  @start
end

Class Method Details

.abort_transaction!Object

Indicate that you don’t want to keep the currently saved transaction information



53
54
55
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 53

def self.abort_transaction!
  current.abort_transaction! if current
end

.current(create_if_empty = nil) ⇒ Object

Return the currently active metric frame, or nil. Call with true to create a new metric frame if one is not already on the thread.



14
15
16
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 14

def self.current(create_if_empty=nil)
  Thread.current[:newrelic_metric_frame] ||= create_if_empty && new
end

.database_metric_nameObject

This is the name of the model currently assigned to database measurements, overriding the default.



20
21
22
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 20

def self.database_metric_name
  current && current.database_metric_name
end

.notice_error(e, custom_params = {}) ⇒ Object

If we have an active metric frame, notice the error and increment the error metric.



102
103
104
105
106
107
108
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 102

def self.notice_error(e, custom_params={})
  if current
    current.notice_error(e, custom_params)
  else
    NewRelic::Agent.instance.error_collector.notice_error(e, nil, nil, custom_params)
  end
end

Instance Method Details

#abort_transaction!Object

Call this to ensure that the current transaction is not saved



58
59
60
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 58

def abort_transaction!
  NewRelic::Agent.instance.transaction_sampler.ignore_transaction
end

#categoryObject



71
72
73
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 71

def category
  @path_stack.last.first  
end

#metric_nameObject



125
126
127
128
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 125

def metric_name
  return nil if @path_stack.empty?
  category + '/' + path 
end

#notice_error(e, custom_params = {}) ⇒ Object



110
111
112
113
114
115
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 110

def notice_error(e, custom_params={})
  if exception != e
    NewRelic::Agent.instance.error_collector.notice_error(e, nil, metric_name, filtered_params.merge(custom_params))
    self.exception = e
  end
end

#pathObject



74
75
76
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 74

def path
  @path_stack.last.last
end

#popObject



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 78

def pop
  category, path = @path_stack.pop
  if category.nil?
    NewRelic::Control.instance.log.error "Underflow in metric frames: #{caller.join("\n   ")}"
  end
  # change the transaction name back to whatever was on the stack.  
  if @path_stack.empty?
    Thread.current[:newrelic_metric_frame] = nil
    if NewRelic::Agent.is_execution_traced?
      cpu_burn = nil
      if @process_cpu_start
        cpu_burn = process_cpu - @process_cpu_start
      elsif @jruby_cpu_start
        cpu_burn = jruby_cpu_time - @jruby_cpu_start
        NewRelic::Agent.get_stats_no_scope(NewRelic::Metrics::USER_TIME).record_data_point(cpu_burn)
      end
      NewRelic::Agent.instance.transaction_sampler.notice_transaction_cpu_time(cpu_burn) if cpu_burn
      NewRelic::Agent.instance.histogram.process(Time.now.to_f - start) if recording_web_transaction?(category)
    end      
  end
  NewRelic::Agent.instance.stats_engine.scope_name = metric_name 
end

#push(category, path) ⇒ Object

Indicate that we are entering a measured controller action or task. Make sure you unwind every push with a pop call.



47
48
49
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 47

def push(category, path)
  @path_stack.push [category, path]
end

#record_apdexObject



116
117
118
119
120
121
122
123
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 116

def record_apdex
  return unless recording_web_transaction?
  ending = Time.now.to_f
  summary_stat = NewRelic::Agent.instance.stats_engine.get_custom_stats("Apdex", NewRelic::ApdexStats)
  controller_stat = NewRelic::Agent.instance.stats_engine.get_custom_stats("Apdex/#{path}", NewRelic::ApdexStats)
  update_apdex(summary_stat, ending - apdex_start, exception)
  update_apdex(controller_stat, ending - start, exception)
end

#recorded_metricsObject

Return the array of metrics to record for the current metric frame.



131
132
133
134
135
136
137
138
139
140
141
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 131

def recorded_metrics
  metrics = [ metric_name ]
  if @path_stack.size == 1
    if recording_web_transaction?
      metrics += ["Controller", "HttpDispatcher"]
    else
      metrics += ["#{category}/all", "OtherTransaction/all"]
    end
  end
  metrics
end

#start_transactionObject

This needs to be called after entering the call to trace the controller action, otherwise the controller action blames itself. It gets reset in the normal #pop call.



63
64
65
66
67
68
69
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 63

def start_transaction
  NewRelic::Agent.instance.stats_engine.start_transaction metric_name
  # Only push the transaction context info once, on entry:
  if @path_stack.size == 1
    NewRelic::Agent.instance.transaction_sampler.notice_transaction(metric_name, available_request, filtered_params)
  end
end

#with_database_metric_name(model, method) ⇒ Object

Yield to a block that is run with a database metric name context. This means the Database instrumentation will use this for the metric name if it does not otherwise know about a model. This is re-entrant.

  • model is the DB model class

  • method is the name of the finder method or other method to identify the operation with.



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/new_relic/agent/instrumentation/metric_frame.rb', line 150

def with_database_metric_name(model, method)
  previous = @database_metric_name
  model_name = case model
  when Class
    model.name
  when String
    model
  else
    model.to_s
  end
  @database_metric_name = "ActiveRecord/#{model_name}/#{method}"
  yield
ensure  
  @database_metric_name=previous
end