Class: NewRelic::Control

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

Overview

The Control is a singleton responsible for the startup and initialization sequence. The initializer uses a LocalEnvironment to detect the framework and instantiates the framework specific subclass.

The Control also implements some of the public API for the agent.

Direct Known Subclasses

Merb, Rails, Rails3, Ruby

Defined Under Namespace

Classes: External, Merb, ProxyServer, Rails, Rails3, Ruby, Server, Sinatra

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#env=(value) ⇒ Object (writeonly)

The env is the setting used to identify which section of the newrelic.yml to load. This defaults to a framework specific value, such as ENV but can be overridden as long as you set it before calling #init_plugin



42
43
44
# File 'lib/new_relic/control.rb', line 42

def env=(value)
  @env = value
end

#local_envObject (readonly)

Returns the value of attribute local_env.



43
44
45
# File 'lib/new_relic/control.rb', line 43

def local_env
  @local_env
end

#log_fileObject

Returns the value of attribute log_file.



38
39
40
# File 'lib/new_relic/control.rb', line 38

def log_file
  @log_file
end

Class Method Details

.format_message(severity, timestamp, progname, msg) ⇒ Object

change the format just for our logger



418
419
420
# File 'lib/new_relic/control.rb', line 418

def @log.format_message(severity, timestamp, progname, msg)
  "[#{timestamp.strftime("%m/%d/%y %H:%M:%S %z")} #{Socket.gethostname} (#{$$})] #{severity} : #{msg}\n" 
end

.instanceObject

Access the Control singleton, lazy initialized



53
54
55
# File 'lib/new_relic/control.rb', line 53

def self.instance
  @instance ||= new_instance
end

Instance Method Details

#[](key) ⇒ Object



125
126
127
# File 'lib/new_relic/control.rb', line 125

def [](key)
  fetch(key)
end

#[]=(key, value) ⇒ Object



146
147
148
# File 'lib/new_relic/control.rb', line 146

def []=(key, value)
  settings[key] = value
end

#add_instrumentation(pattern) ⇒ Object

Add instrumentation. Don’t call this directly. Use NewRelic::Agent#add_instrumentation. This will load the file synchronously if we’ve already loaded the default instrumentation.



327
328
329
330
331
332
333
# File 'lib/new_relic/control.rb', line 327

def add_instrumentation pattern
  if @instrumented
    load_instrumentation_files pattern
  else
    @instrumentation_files << pattern
  end
end

#agent_enabled?Boolean

True if dev mode or monitor mode are enabled, and we are running inside a valid dispatcher like mongrel or passenger. Can be overridden by NEWRELIC_ENABLE env variable, monitor_daemons config option when true, or agent_enabled config option when true or false.

Returns:

  • (Boolean)


200
201
202
203
204
205
206
207
208
209
# File 'lib/new_relic/control.rb', line 200

def agent_enabled?
  return false if !developer_mode? && !monitor_mode?
  return self['agent_enabled'].to_s =~ /true|on|yes/i if !self['agent_enabled'].nil? && self['agent_enabled'] != 'auto'
  return false if ENV['NEWRELIC_ENABLE'].to_s =~ /false|off|no/i 
  return true if self['monitor_daemons'].to_s =~ /true|on|yes/i
  return true if ENV['NEWRELIC_ENABLE'].to_s =~ /true|on|yes/i
  # When in 'auto' mode the agent is enabled if there is a known
  # dispatcher running
  return true if @local_env.dispatcher != nil
end

#apdex_tObject

Agent config conveniences



163
164
165
166
# File 'lib/new_relic/control.rb', line 163

def apdex_t
  # Always initialized with a default
  fetch('apdex_t').to_f
end

#api_serverObject



245
246
247
248
249
250
251
252
# File 'lib/new_relic/control.rb', line 245

def api_server
  api_host = self['api_host'] || 'rpm.newrelic.com' 
  @api_server ||= 
  NewRelic::Control::Server.new \
  api_host, 
   (self['api_port'] || self['port'] || (use_ssl? ? 443 : 80)).to_i, 
  nil
end

#appObject Also known as: framework



211
212
213
# File 'lib/new_relic/control.rb', line 211

def app
  @local_env.framework
end

#app_namesObject



222
223
224
# File 'lib/new_relic/control.rb', line 222

def app_names
  self['app_name'] ? self['app_name'].split(';') : []
end

#capture_paramsObject



170
171
172
# File 'lib/new_relic/control.rb', line 170

def capture_params
  fetch('capture_params')
end

#developer_mode?Boolean

True if we are capturing data and displaying in /newrelic

Returns:

  • (Boolean)


178
179
180
# File 'lib/new_relic/control.rb', line 178

def developer_mode?
  fetch('developer_mode', fetch('developer'))
end

#dispatcherObject



219
220
221
# File 'lib/new_relic/control.rb', line 219

def dispatcher
  (self['dispatcher'] && self['dispatcher'].to_sym) || @local_env.dispatcher
end

#dispatcher_instance_idObject



216
217
218
# File 'lib/new_relic/control.rb', line 216

def dispatcher_instance_id
  self['dispatcher_instance_id'] || @local_env.dispatcher_instance_id
end

#fetch(key, default = nil) ⇒ Object



150
151
152
# File 'lib/new_relic/control.rb', line 150

def fetch(key, default=nil)
  settings.fetch(key, default)
end

#http_connection(host = nil) ⇒ Object

Return the Net::HTTP with proxy configuration given the NewRelic::Control::Server object. Default is the collector but for api calls you need to pass api_server

Experimental support for SSL verification: swap ‘VERIFY_NONE’ for ‘VERIFY_PEER’ line to try it out If verification fails, uncomment the ‘http.ca_file’ line and it will use the included certificate.



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/new_relic/control.rb', line 273

def http_connection(host = nil)
  host ||= server
  # Proxy returns regular HTTP if @proxy_host is nil (the default)
  http_class = Net::HTTP::Proxy(proxy_server.name, proxy_server.port, 
                                proxy_server.user, proxy_server.password)
  http = http_class.new(host.ip || host.name, host.port)
  log.debug("Http Connection opened to #{host.ip||host.name}:#{host.port}")
  if use_ssl?
    http.use_ssl = true
    if verify_certificate?
      http.verify_mode = OpenSSL::SSL::VERIFY_PEER
      http.ca_file = File.join(File.dirname(__FILE__), '..', '..', 'cert', 'cacert.pem')
    else
      http.verify_mode = OpenSSL::SSL::VERIFY_NONE
    end
  end
  http
end

#init_plugin(options = {}) ⇒ Object

Initialize the plugin/gem and start the agent. This does the necessary configuration based on the framework environment and determines whether or not to start the agent. If the agent is not going to be started then it loads the agent shim which has stubs for all the external api.

This may be invoked multiple times, as long as you don’t attempt to uninstall the agent after it has been started.

If the plugin is initialized and it determines that the agent is not enabled, it will skip starting it and install the shim. But if you later call this with :agent_enabled => true, then it will install the real agent and start it.

What determines whether the agent is launched is the result of calling agent_enabled? This will indicate whether the instrumentation should/will be installed. If we’re in a mode where tracers are not installed then we should not start the agent.

Subclasses are not allowed to override, but must implement init_config({}) which is called one or more times.



76
77
78
79
80
81
82
83
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
110
111
112
113
114
115
116
117
118
# File 'lib/new_relic/control.rb', line 76

def init_plugin(options={})
  options['app_name'] = ENV['NEWRELIC_APP_NAME'] if ENV['NEWRELIC_APP_NAME']
 
  require 'new_relic/agent'
  
  # Load the DJ injection now.  If you do it sooner, DJ might not be loaded and
  # you'll miss it.
  require 'new_relic/delayed_job_injection'
  
  # Merge the stringified options into the config as overrides:
  logger_override = options.delete(:log)
  environment_name = options.delete(:env) and self.env = environment_name
  dispatcher = options.delete(:dispatcher) and @local_env.dispatcher = dispatcher 
  dispatcher_instance_id = options.delete(:dispatcher_instance_id) and @local_env.dispatcher_instance_id = dispatcher_instance_id

  # Clear out the settings, if they've already been loaded.  It may be that
  # between calling init_plugin the first time and the second time, the env
  # has been overridden
  @settings = nil
  settings
  merge_options(options)
  if logger_override
    @log = logger_override
    # Try to grab the log filename
    @log_file = @log.instance_eval { @logdev.filename rescue nil }
  end
  # An artifact of earlier implementation, we put both #add_method_tracer and #trace_execution
  # methods in the module methods.
  Module.send :include, NewRelic::Agent::MethodTracer::ClassMethods
  Module.send :include, NewRelic::Agent::MethodTracer::InstanceMethods
  init_config(options)
  NewRelic::Agent.agent = NewRelic::Agent::Agent.instance
  if agent_enabled? && !NewRelic::Agent.instance.started?
    setup_log unless logger_override
    start_agent
    install_instrumentation
    load_samplers unless self['disable_samplers']
    local_env.gather_environment_info
    append_environment_info
  elsif !agent_enabled?
    install_shim
  end
end

#install_instrumentationObject



334
335
336
337
338
339
340
341
342
343
344
345
346
347
# File 'lib/new_relic/control.rb', line 334

def install_instrumentation
  return if @instrumented
  
  @instrumented = true
  
  # Instrumentation for the key code points inside rails for monitoring by NewRelic.
  # note this file is loaded only if the newrelic agent is enabled (through config/newrelic.yml)
  instrumentation_path = File.join(File.dirname(__FILE__), 'agent','instrumentation')
  @instrumentation_files <<
  File.join(instrumentation_path, '*.rb') <<
  File.join(instrumentation_path, app.to_s, '*.rb')
  @instrumentation_files.each { | pattern |  load_instrumentation_files pattern }
  log.debug "Finished instrumentation"
end

#install_shimObject

Install stubs to the proper location so the app code will not fail if the agent is not running.



317
318
319
320
321
# File 'lib/new_relic/control.rb', line 317

def install_shim
  # Once we install instrumentation, you can't undo that by installing the shim.
  raise "Cannot install the Agent shim after instrumentation has already been installed!" if @instrumented
  NewRelic::Agent.agent = NewRelic::Agent::ShimAgent.instance
end

#license_keyObject



167
168
169
# File 'lib/new_relic/control.rb', line 167

def license_key
  fetch('license_key')
end

#load_samplersObject



349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
# File 'lib/new_relic/control.rb', line 349

def load_samplers
  agent = NewRelic::Agent.instance
  NewRelic::Agent::Sampler.sampler_classes.each do | subclass |
    begin
      log.debug "#{subclass.name} not supported on this platform." and next if not subclass.supported_on_this_platform?
      sampler = subclass.new
      if subclass.use_harvest_sampler?
        agent.stats_engine.add_harvest_sampler sampler
        log.debug "Registered #{subclass.name} for harvest time sampling"
      else            
        agent.stats_engine.add_sampler sampler
        log.debug "Registered #{subclass.name} for periodic sampling"
      end
    rescue NewRelic::Agent::Sampler::Unsupported => e
      log.info "#{subclass} sampler not available: #{e}"
    rescue => e
      log.error "Error registering sampler: #{e}, #{e.backtrace.join("\n")}"
    end
  end
end

#logObject



295
296
297
298
299
300
301
302
303
# File 'lib/new_relic/control.rb', line 295

def log
  # If we try to get a log before one has been set up, return a stdout log
  unless @log
    l = Logger.new(STDOUT)
    l.level = Logger::INFO
    return l
  end
  @log
end

#log!(msg, level = :info) ⇒ Object

send the given message to STDOUT so that it shows up in the console. This should be used for important informational messages at boot. The to_stdout may be implemented differently by different config subclasses. This will NOT print anything if tracers are not enabled



309
310
311
312
313
# File 'lib/new_relic/control.rb', line 309

def log!(msg, level=:info)
  return if @settings && !agent_enabled?
  to_stdout msg
  log.send level, msg if @log
end

#monitor_mode?Boolean

True if we are sending data to the server, monitoring production

Returns:

  • (Boolean)


174
175
176
# File 'lib/new_relic/control.rb', line 174

def monitor_mode?
  fetch('monitor_mode', fetch('enabled'))
end

#multi_threaded?Boolean

True if the app runs in multi-threaded mode

Returns:

  • (Boolean)


182
183
184
# File 'lib/new_relic/control.rb', line 182

def multi_threaded?
  fetch('multi_threaded')
end

#post_size_limitObject



189
190
191
# File 'lib/new_relic/control.rb', line 189

def post_size_limit
  fetch('post_size_limit', 2 * 1024 * 1024)
end

#profiling=(val) ⇒ Object

Set the flag for capturing profiles in dev mode. If RubyProf is not loaded a true value is ignored.



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

def profiling=(val)
  @profiling = profiling_available? && val && defined?(RubyProf)
end

#profiling?Boolean

A flag used in dev mode to indicate if profiling is available

Returns:

  • (Boolean)


21
22
23
# File 'lib/new_relic/control.rb', line 21

def profiling?
  @profiling
end

#profiling_available?Boolean

Returns:

  • (Boolean)


25
26
27
28
29
30
31
# File 'lib/new_relic/control.rb', line 25

def profiling_available?
  @profiling_available ||= 
  begin
    require 'ruby-prof'
    true
  rescue LoadError; end
end

#proxy_serverObject



254
255
256
257
# File 'lib/new_relic/control.rb', line 254

def proxy_server
  @proxy_server ||=
  NewRelic::Control::ProxyServer.new self['proxy_host'], self['proxy_port'], self['proxy_user'], self['proxy_pass'] 
end

#serverObject



241
242
243
# File 'lib/new_relic/control.rb', line 241

def server
  @remote_server ||= server_from_host(nil)  
end

#server_from_host(hostname = nil) ⇒ Object



259
260
261
262
263
264
# File 'lib/new_relic/control.rb', line 259

def server_from_host(hostname=nil)
  host = hostname || self['host'] || 'collector.newrelic.com'
  
  # if the host is not an IP address, turn it into one
  NewRelic::Control::Server.new host, (self['port'] || (use_ssl? ? 443 : 80)).to_i, convert_to_ip_address(host) 
end

#settingsObject



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/new_relic/control.rb', line 129

def settings
  unless @settings
    @settings = (@yaml && merge_defaults(@yaml[env])) || {}
    # At the time we bind the settings, we also need to run this little piece
    # of magic which allows someone to augment the id with the app name, necessary
    if self['multi_homed'] && app_names.size > 0
      if @local_env.dispatcher_instance_id
        @local_env.dispatcher_instance_id << ":#{app_names.first}"
      else
        @local_env.dispatcher_instance_id = app_names.first
      end
    end
    
  end
  @settings
end

#start_agentObject

Install the real agent into the Agent module, and issue the start command.



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

def start_agent
  NewRelic::Agent.agent.start
end

#sync_startupObject



193
194
195
# File 'lib/new_relic/control.rb', line 193

def sync_startup
  fetch('sync_startup', false)
end

#to_sObject



291
292
293
# File 'lib/new_relic/control.rb', line 291

def to_s
  "Control[#{self.app}]"
end

#use_ssl?Boolean

Returns:

  • (Boolean)


232
233
234
# File 'lib/new_relic/control.rb', line 232

def use_ssl?
  @use_ssl ||= fetch('ssl', false)
end

#use_textmate?Boolean

True if we should view files in textmate

Returns:

  • (Boolean)


186
187
188
# File 'lib/new_relic/control.rb', line 186

def use_textmate?
  fetch('textmate')
end

#validate_seedObject



225
226
227
# File 'lib/new_relic/control.rb', line 225

def validate_seed
  self['validate_seed'] || ENV['NR_VALIDATE_SEED']   
end

#validate_tokenObject



228
229
230
# File 'lib/new_relic/control.rb', line 228

def validate_token
  self['validate_token'] || ENV['NR_VALIDATE_TOKEN']
end

#verify_certificate?Boolean

Returns:

  • (Boolean)


236
237
238
239
# File 'lib/new_relic/control.rb', line 236

def verify_certificate?
  #this can only be on when SSL is enabled
  @verify_certificate ||= ( use_ssl? ? fetch('verify_certificate', false) : false)
end