Module: NewRelic::Agent::Agent::InstanceMethods

Included in:
NewRelic::Agent::Agent
Defined in:
lib/new_relic/agent/agent.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#error_collectorObject (readonly)

Returns the value of attribute error_collector.



59
60
61
# File 'lib/new_relic/agent/agent.rb', line 59

def error_collector
  @error_collector
end

#histogramObject (readonly)

Returns the value of attribute histogram.



61
62
63
# File 'lib/new_relic/agent/agent.rb', line 61

def histogram
  @histogram
end

#metric_idsObject (readonly)

Returns the value of attribute metric_ids.



62
63
64
# File 'lib/new_relic/agent/agent.rb', line 62

def metric_ids
  @metric_ids
end

#obfuscatorObject (readonly)

Returns the value of attribute obfuscator.



56
57
58
# File 'lib/new_relic/agent/agent.rb', line 56

def obfuscator
  @obfuscator
end

#record_sqlObject (readonly)

Returns the value of attribute record_sql.



60
61
62
# File 'lib/new_relic/agent/agent.rb', line 60

def record_sql
  @record_sql
end

#stats_engineObject (readonly)

Returns the value of attribute stats_engine.



57
58
59
# File 'lib/new_relic/agent/agent.rb', line 57

def stats_engine
  @stats_engine
end

#transaction_samplerObject (readonly)

Returns the value of attribute transaction_sampler.



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

def transaction_sampler
  @transaction_sampler
end

#url_rulesObject (readonly)

Returns the value of attribute url_rules.



63
64
65
# File 'lib/new_relic/agent/agent.rb', line 63

def url_rules
  @url_rules
end

Instance Method Details

#after_fork(options = {}) ⇒ Object

This method should be called in a forked process after a fork. It assumes the parent process initialized the agent, but does not assume the agent started.

The call is idempotent, but not re-entrant.

  • It clears any metrics carried over from the parent process

  • Restarts the sampler thread if necessary

  • Initiates a new agent run and worker loop unless that was done in the parent process and :force_reconnect is not true

Options:

  • :force_reconnect => true to force the spawned process to establish a new connection, such as when forking a long running process. The default is false–it will only connect to the server if the parent had not connected.

  • :keep_retrying => false if we try to initiate a new connection, this tells me to only try it once so this method returns quickly if there is some kind of latency with the server.



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/new_relic/agent/agent.rb', line 121

def after_fork(options={})

  # @connected gets false after we fail to connect or have an error
  # connecting.  @connected has nil if we haven't finished trying to connect.
  # or we didn't attempt a connection because this is the master process

  # log.debug "Agent received after_fork notice in #$$: [#{control.agent_enabled?}; monitor=#{control.monitor_mode?}; connected: #{@connected.inspect}; thread=#{@worker_thread.inspect}]"
  return if !control.agent_enabled? or
    !control.monitor_mode? or
    @connected == false or
    @worker_thread && @worker_thread.alive?

  log.info "Starting the worker thread in #$$ after forking."

  # Clear out stats that are left over from parent process
  reset_stats

  # Don't ever check to see if this is a spawner.  If we're in a forked process
  # I'm pretty sure we're not also forking new instances.
  start_worker_thread(options)
  @stats_engine.start_sampler_thread
end

#connected?Boolean

Return nil if not yet connected, true if successfully started and false if we failed to start.

Returns:

  • (Boolean)


151
152
153
# File 'lib/new_relic/agent/agent.rb', line 151

def connected?
  @connected
end

#end_transactionObject



187
188
189
# File 'lib/new_relic/agent/agent.rb', line 187

def end_transaction
  @stats_engine.end_transaction
end

#logObject



226
227
228
# File 'lib/new_relic/agent/agent.rb', line 226

def log
  NewRelic::Agent.logger
end

#manual_start(ignored = nil, also_ignored = nil) ⇒ Object

This method is deprecated. Use NewRelic::Agent.manual_start



98
99
100
# File 'lib/new_relic/agent/agent.rb', line 98

def manual_start(ignored=nil, also_ignored=nil)
  raise "This method no longer supported.  Instead use the class method NewRelic::Agent.manual_start"
end

#pop_trace_execution_flagObject

Pop the current trace execution status. Restore trace execution status to what it was before we pushed the current flag.



210
211
212
# File 'lib/new_relic/agent/agent.rb', line 210

def pop_trace_execution_flag
  Thread.current[:newrelic_untraced].pop if Thread.current[:newrelic_untraced]
end

#push_trace_execution_flag(should_trace = false) ⇒ Object

Push flag indicating whether we should be tracing in this thread.



204
205
206
# File 'lib/new_relic/agent/agent.rb', line 204

def push_trace_execution_flag(should_trace=false)
  (Thread.current[:newrelic_untraced] ||= []) << should_trace
end

#record_transaction(duration_seconds, options = {}) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/new_relic/agent/agent.rb', line 65

def record_transaction(duration_seconds, options={})
  is_error = options['is_error'] || options['error_message'] || options['exception']
  metric = options['metric']
  metric ||= options['uri'] # normalize this with url rules
  raise "metric or uri arguments required" unless metric
  metric_info = NewRelic::MetricParser.for_metric_named(metric)

  if metric_info.is_web_transaction?
    NewRelic::Agent::Instrumentation::MetricFrame.record_apdex(metric_info, duration_seconds, duration_seconds, is_error)
    histogram.process(duration_seconds)
  end
  metrics = metric_info.summary_metrics

  metrics << metric
  metrics.each do |name|
    stats = stats_engine.get_stats_no_scope(name)
    stats.record_data_point(duration_seconds)
  end

  if is_error
    if options['exception']
      e = options['exception']
    elsif options['error_message']
      e = Exception.new options['error_message']
    else
      e = Exception.new 'Unknown Error'
    end
    error_collector.notice_error e, :uri => options['uri'], :metric => metric
  end
  # busy time ?
end

#reset_statsObject

Clear out the metric data, errors, and transaction traces. Reset the histogram data.



306
307
308
309
310
311
312
313
314
# File 'lib/new_relic/agent/agent.rb', line 306

def reset_stats
  @stats_engine.reset_stats
  @unsent_errors = []
  @traces = nil
  @unsent_timeslice_data = {}
  @last_harvest_time = Time.now
  @launch_time = Time.now
  @histogram = NewRelic::Histogram.new(NewRelic::Control.instance.apdex_t / 10)
end

#set_record_sql(should_record) ⇒ Object



191
192
193
194
195
# File 'lib/new_relic/agent/agent.rb', line 191

def set_record_sql(should_record)
  prev = Thread::current[:record_sql]
  Thread::current[:record_sql] = should_record
  prev.nil? || prev
end

#set_record_tt(should_record) ⇒ Object



197
198
199
200
201
# File 'lib/new_relic/agent/agent.rb', line 197

def set_record_tt(should_record)
  prev = Thread::current[:record_tt]
  Thread::current[:record_tt] = should_record
  prev.nil? || prev
end

#set_sql_obfuscator(type, &block) ⇒ Object



214
215
216
217
218
219
220
221
222
223
224
# File 'lib/new_relic/agent/agent.rb', line 214

def set_sql_obfuscator(type, &block)
  if type == :before
    @obfuscator = NewRelic::ChainedCall.new(block, @obfuscator)
  elsif type == :after
    @obfuscator = NewRelic::ChainedCall.new(@obfuscator, block)
  elsif type == :replace
    @obfuscator = block
  else
    fail "unknown sql_obfuscator type #{type}"
  end
end

#shutdownObject

Attempt a graceful shutdown of the agent.



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/new_relic/agent/agent.rb', line 156

def shutdown
  return if not started?
  if @worker_loop
    @worker_loop.stop

    log.debug "Starting Agent shutdown"

    # if litespeed, then ignore all future SIGUSR1 - it's
    # litespeed trying to shut us down

    if control.dispatcher == :litespeed
      Signal.trap("SIGUSR1", "IGNORE")
      Signal.trap("SIGTERM", "IGNORE")
    end

    begin
      NewRelic::Agent.disable_all_tracing do
        graceful_disconnect
      end
    rescue => e
      log.error e
      log.error e.backtrace.join("\n")
    end
  end
  @started = nil
end

#startObject

Start up the agent. This verifies that the agent_enabled? is true and initializes the sampler based on the current configuration settings. Then it will fire up the background thread for sending data to the server if applicable.



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'lib/new_relic/agent/agent.rb', line 234

def start
  if started?
    control.log! "Agent Started Already!", :error
    return
  end
  return if !control.agent_enabled?
  @started = true
  @local_host = determine_host

  if control.dispatcher.nil? || control.dispatcher.to_s.empty?
    log.info "No dispatcher detected."
  else
    log.info "Dispatcher: #{control.dispatcher.to_s}"
  end
  log.info "Application: #{control.app_names.join(", ")}" unless control.app_names.empty?

  sampler_config = control.fetch('transaction_tracer', {})
  # TODO: Should move this state into the transaction sampler instance
  @should_send_samples = @config_should_send_samples = sampler_config.fetch('enabled', true)
  @should_send_random_samples = sampler_config.fetch('random_sample', false)
  @explain_threshold = sampler_config.fetch('explain_threshold', 0.5).to_f
  @explain_enabled = sampler_config.fetch('explain_enabled', true)
  @record_sql = sampler_config.fetch('record_sql', :obfuscated).to_sym

  # use transaction_threshold: 4.0 to force the TT collection
  # threshold to 4 seconds
  # use transaction_threshold: apdex_f to use your apdex t value
  # multiplied by 4
  # undefined transaction_threshold defaults to 2.0
  apdex_f = 4 * NewRelic::Control.instance.apdex_t
  @slowest_transaction_threshold = sampler_config.fetch('transaction_threshold', 2.0)
  if @slowest_transaction_threshold =~ /apdex_f/i
    @slowest_transaction_threshold = apdex_f
  end
  @slowest_transaction_threshold = @slowest_transaction_threshold.to_f

  log.warn "Agent is configured to send raw SQL to RPM service" if @record_sql == :raw

  case
  when !control.monitor_mode?
    log.warn "Agent configured not to send data in this environment - edit newrelic.yml to change this"
  when !control.license_key
    log.error "No license key found.  Please edit your newrelic.yml file and insert your license key."
  when control.license_key.length != 40
    log.error "Invalid license key: #{control.license_key}"
  when [:passenger, :unicorn].include?(control.dispatcher)
    log.info "Connecting workers after forking."
  else
    # Do the connect in the foreground if we are in sync mode
    NewRelic::Agent.disable_all_tracing { connect(:keep_retrying => false) } if control.sync_startup

    # Start the event loop and initiate connection if necessary
    start_worker_thread

    # Our shutdown handler needs to run after other shutdown handlers
    # that may be doing things like running the app (hello sinatra).
    if control.send_data_on_exit
      if RUBY_VERSION =~ /rubinius/i
        list = at_exit { shutdown }
        # move the shutdown handler to the front of the list, to
        # execute last:
        list.unshift(list.pop)
      elsif !defined?(JRuby) or !defined?(Sinatra::Application)
        at_exit { at_exit { shutdown } }
      end
    end
  end
  log.info "New Relic RPM Agent #{NewRelic::VERSION::STRING} Initialized: pid = #$$"
  log.info "Agent Log found in #{NewRelic::Control.instance.log_file}" if NewRelic::Control.instance.log_file
end

#start_transactionObject



183
184
185
# File 'lib/new_relic/agent/agent.rb', line 183

def start_transaction
  @stats_engine.start_transaction
end

#started?Boolean

True if we have initialized and completed ‘start’

Returns:

  • (Boolean)


145
146
147
# File 'lib/new_relic/agent/agent.rb', line 145

def started?
  @started
end