Class: NewRelic::Control

Inherits:
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, Ruby

Defined Under Namespace

Classes: External, Merb, ProxyServer, Rails, 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



399
400
401
# File 'lib/new_relic/control.rb', line 399

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



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

def [](key)
  fetch(key)
end

#[]=(key, value) ⇒ Object



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

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.



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

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)


188
189
190
191
192
193
194
195
196
197
# File 'lib/new_relic/control.rb', line 188

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



155
156
157
158
# File 'lib/new_relic/control.rb', line 155

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

#api_serverObject



227
228
229
230
231
232
233
234
# File 'lib/new_relic/control.rb', line 227

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



199
200
201
# File 'lib/new_relic/control.rb', line 199

def app
  @local_env.framework
end

#app_namesObject



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

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

#capture_paramsObject



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

def capture_params
  fetch('capture_params')
end

#developer_mode?Boolean

True if we are capturing data and displaying in /newrelic

Returns:

  • (Boolean)


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

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

#dispatcherObject



207
208
209
# File 'lib/new_relic/control.rb', line 207

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

#dispatcher_instance_idObject



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

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

#fetch(key, default = nil) ⇒ Object



142
143
144
# File 'lib/new_relic/control.rb', line 142

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.



255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/new_relic/control.rb', line 255

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)
  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 at most once.



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
# File 'lib/new_relic/control.rb', line 76

def init_plugin(options={})
  require 'new_relic/agent'
  # Merge the stringified options into the config as overrides:
  logger_override = options.delete(:log)
  environment_name = options.delete(:env)
  self.env = environment_name if environment_name
  # 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
  
  options.each { |sym, val | self[sym.to_s] = val unless sym == :config }
  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)
  if agent_enabled? && !@started
    setup_log unless logger_override
    start_agent
    install_instrumentation
    load_samplers unless self['disable_samplers']
    local_env.gather_environment_info
    append_environment_info
    @started = true
  elsif !agent_enabled?
    install_shim
  end
end

#install_instrumentationObject



315
316
317
318
319
320
321
322
323
324
325
326
327
328
# File 'lib/new_relic/control.rb', line 315

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.



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

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



159
160
161
# File 'lib/new_relic/control.rb', line 159

def license_key
  fetch('license_key')
end

#load_samplersObject



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

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.info "Registered #{subclass.name} for harvest time sampling"
      else            
        agent.stats_engine.add_sampler sampler
        log.info "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



276
277
278
279
280
281
282
283
284
# File 'lib/new_relic/control.rb', line 276

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



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

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)


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

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

#multi_threaded?Boolean

True if the app runs in multi-threaded mode

Returns:

  • (Boolean)


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

def multi_threaded?
  fetch('multi_threaded')
end

#post_size_limitObject



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

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



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

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

#serverObject



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

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

#server_from_host(hostname = nil) ⇒ Object



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

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



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/new_relic/control.rb', line 121

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.



112
113
114
115
# File 'lib/new_relic/control.rb', line 112

def start_agent
  NewRelic::Agent.agent = NewRelic::Agent::Agent.instance
  NewRelic::Agent.agent.start
end

#to_sObject



272
273
274
# File 'lib/new_relic/control.rb', line 272

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

#use_ssl?Boolean

Returns:

  • (Boolean)


214
215
216
# File 'lib/new_relic/control.rb', line 214

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

#use_textmate?Boolean

True if we should view files in textmate

Returns:

  • (Boolean)


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

def use_textmate?
  fetch('textmate')
end

#verify_certificate?Boolean

Returns:

  • (Boolean)


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

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