Class: NewRelic::Agent::Agent

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

Overview

The Agent is a singleton that is instantiated when the plugin is activated.

Direct Known Subclasses

ShimAgent

Constant Summary collapse

PROTOCOL_VERSION =

Specifies the version of the agent’s communication protocol with the NewRelic hosted site.

8

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#error_collectorObject (readonly)

Returns the value of attribute error_collector.



34
35
36
# File 'lib/new_relic/agent/agent.rb', line 34

def error_collector
  @error_collector
end

#histogramObject (readonly)

Returns the value of attribute histogram.



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

def histogram
  @histogram
end

#metric_idsObject (readonly)

Returns the value of attribute metric_ids.



37
38
39
# File 'lib/new_relic/agent/agent.rb', line 37

def metric_ids
  @metric_ids
end

#obfuscatorObject (readonly)

Returns the value of attribute obfuscator.



31
32
33
# File 'lib/new_relic/agent/agent.rb', line 31

def obfuscator
  @obfuscator
end

#record_sqlObject (readonly)

Returns the value of attribute record_sql.



35
36
37
# File 'lib/new_relic/agent/agent.rb', line 35

def record_sql
  @record_sql
end

#stats_engineObject (readonly)

Returns the value of attribute stats_engine.



32
33
34
# File 'lib/new_relic/agent/agent.rb', line 32

def stats_engine
  @stats_engine
end

#transaction_samplerObject (readonly)

Returns the value of attribute transaction_sampler.



33
34
35
# File 'lib/new_relic/agent/agent.rb', line 33

def transaction_sampler
  @transaction_sampler
end

Class Method Details

.instanceObject

Should only be called by NewRelic::Control



40
41
42
# File 'lib/new_relic/agent/agent.rb', line 40

def self.instance
  @instance ||= self.new
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.

  • 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.



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/new_relic/agent/agent.rb', line 65

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
  
  start_worker_thread(options)
  @stats_engine.start_sampler_thread
end

#end_transactionObject



121
122
123
# File 'lib/new_relic/agent/agent.rb', line 121

def end_transaction
  @stats_engine.end_transaction
end

#logObject



160
161
162
# File 'lib/new_relic/agent/agent.rb', line 160

def log
  NewRelic::Agent.logger
end

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

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



44
45
46
# File 'lib/new_relic/agent/agent.rb', line 44

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.



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

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.



138
139
140
# File 'lib/new_relic/agent/agent.rb', line 138

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

#reset_statsObject

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



241
242
243
244
245
246
247
248
249
# File 'lib/new_relic/agent/agent.rb', line 241

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



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

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



131
132
133
134
135
# File 'lib/new_relic/agent/agent.rb', line 131

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



148
149
150
151
152
153
154
155
156
157
158
# File 'lib/new_relic/agent/agent.rb', line 148

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.



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/new_relic/agent/agent.rb', line 92

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
      graceful_disconnect
    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.



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/new_relic/agent/agent.rb', line 168

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', {})
  @should_send_samples = sampler_config.fetch('enabled', true)
  log.info "Transaction tracing not enabled." if not @should_send_samples
  
  @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
  
  @explain_threshold = sampler_config.fetch('explain_threshold', 0.5).to_f
  @explain_enabled = sampler_config.fetch('explain_enabled', true)
  @random_sample = sampler_config.fetch('random_sample', false)
  log.warn "Agent is configured to send raw SQL to RPM service" if @record_sql == :raw
  # Initialize transaction sampler
  @transaction_sampler.random_sampling = @random_sample

  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 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
  control.log! "New Relic RPM Agent #{NewRelic::VERSION::STRING} Initialized: pid = #$$"
  control.log! "Agent Log found in #{NewRelic::Control.instance.log_file}" if NewRelic::Control.instance.log_file
end

#start_transactionObject



117
118
119
# File 'lib/new_relic/agent/agent.rb', line 117

def start_transaction
  @stats_engine.start_transaction
end

#started?Boolean

True if we have initialized and completed ‘start’

Returns:

  • (Boolean)


87
88
89
# File 'lib/new_relic/agent/agent.rb', line 87

def started?
  @started
end