onyx_newrelic_rpm 2.12.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (165) hide show
  1. data/CHANGELOG +436 -0
  2. data/LICENSE +37 -0
  3. data/README.md +138 -0
  4. data/bin/mongrel_rpm +33 -0
  5. data/bin/newrelic_cmd +4 -0
  6. data/cert/cacert.pem +34 -0
  7. data/install.rb +46 -0
  8. data/lib/new_relic/agent/agent.rb +668 -0
  9. data/lib/new_relic/agent/busy_calculator.rb +91 -0
  10. data/lib/new_relic/agent/chained_call.rb +13 -0
  11. data/lib/new_relic/agent/error_collector.rb +128 -0
  12. data/lib/new_relic/agent/instrumentation/active_merchant.rb +18 -0
  13. data/lib/new_relic/agent/instrumentation/active_record_instrumentation.rb +92 -0
  14. data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +45 -0
  15. data/lib/new_relic/agent/instrumentation/authlogic.rb +8 -0
  16. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +404 -0
  17. data/lib/new_relic/agent/instrumentation/data_mapper.rb +90 -0
  18. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +22 -0
  19. data/lib/new_relic/agent/instrumentation/memcache.rb +40 -0
  20. data/lib/new_relic/agent/instrumentation/merb/controller.rb +26 -0
  21. data/lib/new_relic/agent/instrumentation/merb/errors.rb +9 -0
  22. data/lib/new_relic/agent/instrumentation/metric_frame.rb +307 -0
  23. data/lib/new_relic/agent/instrumentation/net.rb +17 -0
  24. data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +22 -0
  25. data/lib/new_relic/agent/instrumentation/rack.rb +112 -0
  26. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +59 -0
  27. data/lib/new_relic/agent/instrumentation/rails/action_web_service.rb +27 -0
  28. data/lib/new_relic/agent/instrumentation/rails/errors.rb +24 -0
  29. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +45 -0
  30. data/lib/new_relic/agent/instrumentation/rails3/errors.rb +21 -0
  31. data/lib/new_relic/agent/instrumentation/sinatra.rb +46 -0
  32. data/lib/new_relic/agent/instrumentation/sunspot.rb +17 -0
  33. data/lib/new_relic/agent/instrumentation/unicorn_instrumentation.rb +10 -0
  34. data/lib/new_relic/agent/method_tracer.rb +350 -0
  35. data/lib/new_relic/agent/sampler.rb +46 -0
  36. data/lib/new_relic/agent/samplers/cpu_sampler.rb +54 -0
  37. data/lib/new_relic/agent/samplers/delayed_job_lock_sampler.rb +37 -0
  38. data/lib/new_relic/agent/samplers/memory_sampler.rb +142 -0
  39. data/lib/new_relic/agent/samplers/object_sampler.rb +24 -0
  40. data/lib/new_relic/agent/shim_agent.rb +21 -0
  41. data/lib/new_relic/agent/stats_engine/metric_stats.rb +118 -0
  42. data/lib/new_relic/agent/stats_engine/samplers.rb +80 -0
  43. data/lib/new_relic/agent/stats_engine/transactions.rb +149 -0
  44. data/lib/new_relic/agent/stats_engine.rb +24 -0
  45. data/lib/new_relic/agent/transaction_sampler.rb +315 -0
  46. data/lib/new_relic/agent/worker_loop.rb +80 -0
  47. data/lib/new_relic/agent.rb +369 -0
  48. data/lib/new_relic/collection_helper.rb +69 -0
  49. data/lib/new_relic/commands/deployments.rb +145 -0
  50. data/lib/new_relic/commands/new_relic_commands.rb +30 -0
  51. data/lib/new_relic/control/external.rb +13 -0
  52. data/lib/new_relic/control/merb.rb +24 -0
  53. data/lib/new_relic/control/rails.rb +151 -0
  54. data/lib/new_relic/control/rails3.rb +75 -0
  55. data/lib/new_relic/control/ruby.rb +36 -0
  56. data/lib/new_relic/control/sinatra.rb +18 -0
  57. data/lib/new_relic/control.rb +528 -0
  58. data/lib/new_relic/delayed_job_injection.rb +27 -0
  59. data/lib/new_relic/histogram.rb +89 -0
  60. data/lib/new_relic/local_environment.rb +333 -0
  61. data/lib/new_relic/merbtasks.rb +6 -0
  62. data/lib/new_relic/metric_data.rb +42 -0
  63. data/lib/new_relic/metric_parser/action_mailer.rb +9 -0
  64. data/lib/new_relic/metric_parser/active_merchant.rb +26 -0
  65. data/lib/new_relic/metric_parser/active_record.rb +25 -0
  66. data/lib/new_relic/metric_parser/controller.rb +54 -0
  67. data/lib/new_relic/metric_parser/controller_cpu.rb +38 -0
  68. data/lib/new_relic/metric_parser/errors.rb +6 -0
  69. data/lib/new_relic/metric_parser/external.rb +50 -0
  70. data/lib/new_relic/metric_parser/mem_cache.rb +50 -0
  71. data/lib/new_relic/metric_parser/other_transaction.rb +15 -0
  72. data/lib/new_relic/metric_parser/view.rb +61 -0
  73. data/lib/new_relic/metric_parser/web_frontend.rb +14 -0
  74. data/lib/new_relic/metric_parser/web_service.rb +9 -0
  75. data/lib/new_relic/metric_parser.rb +125 -0
  76. data/lib/new_relic/metric_spec.rb +67 -0
  77. data/lib/new_relic/metrics.rb +9 -0
  78. data/lib/new_relic/noticed_error.rb +24 -0
  79. data/lib/new_relic/rack/metric_app.rb +58 -0
  80. data/lib/new_relic/rack/mongrel_rpm.ru +25 -0
  81. data/lib/new_relic/rack/newrelic.yml +26 -0
  82. data/lib/new_relic/rack_app.rb +5 -0
  83. data/lib/new_relic/recipes.rb +82 -0
  84. data/lib/new_relic/stats.rb +376 -0
  85. data/lib/new_relic/transaction_analysis.rb +124 -0
  86. data/lib/new_relic/transaction_sample.rb +654 -0
  87. data/lib/new_relic/version.rb +55 -0
  88. data/lib/new_relic_api.rb +276 -0
  89. data/lib/newrelic_rpm.rb +40 -0
  90. data/lib/tasks/all.rb +4 -0
  91. data/lib/tasks/install.rake +7 -0
  92. data/lib/tasks/tests.rake +15 -0
  93. data/newrelic.yml +235 -0
  94. data/onyx_newrelic_rpm.gemspec +221 -0
  95. data/recipes/newrelic.rb +6 -0
  96. data/test/active_record_fixtures.rb +55 -0
  97. data/test/config/newrelic.yml +43 -0
  98. data/test/config/test_control.rb +38 -0
  99. data/test/new_relic/agent/active_record_instrumentation_test.rb +287 -0
  100. data/test/new_relic/agent/agent_controller_test.rb +280 -0
  101. data/test/new_relic/agent/agent_test_controller.rb +82 -0
  102. data/test/new_relic/agent/busy_calculator_test.rb +79 -0
  103. data/test/new_relic/agent/collection_helper_test.rb +125 -0
  104. data/test/new_relic/agent/error_collector_test.rb +171 -0
  105. data/test/new_relic/agent/memcache_instrumentation_test.rb +103 -0
  106. data/test/new_relic/agent/method_tracer_test.rb +340 -0
  107. data/test/new_relic/agent/metric_data_test.rb +56 -0
  108. data/test/new_relic/agent/metric_frame_test.rb +51 -0
  109. data/test/new_relic/agent/mock_ar_connection.rb +40 -0
  110. data/test/new_relic/agent/mock_scope_listener.rb +23 -0
  111. data/test/new_relic/agent/net_instrumentation_test.rb +77 -0
  112. data/test/new_relic/agent/rpm_agent_test.rb +138 -0
  113. data/test/new_relic/agent/stats_engine/metric_stats_test.rb +79 -0
  114. data/test/new_relic/agent/stats_engine/samplers_test.rb +72 -0
  115. data/test/new_relic/agent/stats_engine/stats_engine_test.rb +184 -0
  116. data/test/new_relic/agent/task_instrumentation_test.rb +193 -0
  117. data/test/new_relic/agent/testable_agent.rb +13 -0
  118. data/test/new_relic/agent/transaction_sample_builder_test.rb +195 -0
  119. data/test/new_relic/agent/transaction_sample_test.rb +186 -0
  120. data/test/new_relic/agent/transaction_sampler_test.rb +385 -0
  121. data/test/new_relic/agent/worker_loop_test.rb +60 -0
  122. data/test/new_relic/control_test.rb +117 -0
  123. data/test/new_relic/deployments_api_test.rb +69 -0
  124. data/test/new_relic/environment_test.rb +75 -0
  125. data/test/new_relic/metric_parser_test.rb +172 -0
  126. data/test/new_relic/metric_spec_test.rb +177 -0
  127. data/test/new_relic/shim_agent_test.rb +9 -0
  128. data/test/new_relic/stats_test.rb +311 -0
  129. data/test/new_relic/version_number_test.rb +89 -0
  130. data/test/test_helper.rb +53 -0
  131. data/test/ui/newrelic_controller_test.rb +14 -0
  132. data/test/ui/newrelic_helper_test.rb +53 -0
  133. data/ui/controllers/newrelic_controller.rb +220 -0
  134. data/ui/helpers/google_pie_chart.rb +49 -0
  135. data/ui/helpers/newrelic_helper.rb +319 -0
  136. data/ui/views/layouts/newrelic_default.rhtml +47 -0
  137. data/ui/views/newrelic/_explain_plans.rhtml +27 -0
  138. data/ui/views/newrelic/_sample.rhtml +19 -0
  139. data/ui/views/newrelic/_segment.rhtml +28 -0
  140. data/ui/views/newrelic/_segment_limit_message.rhtml +1 -0
  141. data/ui/views/newrelic/_segment_row.rhtml +14 -0
  142. data/ui/views/newrelic/_show_sample_detail.rhtml +24 -0
  143. data/ui/views/newrelic/_show_sample_sql.rhtml +20 -0
  144. data/ui/views/newrelic/_show_sample_summary.rhtml +3 -0
  145. data/ui/views/newrelic/_sql_row.rhtml +11 -0
  146. data/ui/views/newrelic/_stack_trace.rhtml +30 -0
  147. data/ui/views/newrelic/_table.rhtml +12 -0
  148. data/ui/views/newrelic/explain_sql.rhtml +42 -0
  149. data/ui/views/newrelic/images/arrow-close.png +0 -0
  150. data/ui/views/newrelic/images/arrow-open.png +0 -0
  151. data/ui/views/newrelic/images/blue_bar.gif +0 -0
  152. data/ui/views/newrelic/images/file_icon.png +0 -0
  153. data/ui/views/newrelic/images/gray_bar.gif +0 -0
  154. data/ui/views/newrelic/images/new-relic-rpm-desktop.gif +0 -0
  155. data/ui/views/newrelic/images/new_relic_rpm_desktop.gif +0 -0
  156. data/ui/views/newrelic/images/textmate.png +0 -0
  157. data/ui/views/newrelic/index.rhtml +57 -0
  158. data/ui/views/newrelic/javascript/prototype-scriptaculous.js +7288 -0
  159. data/ui/views/newrelic/javascript/transaction_sample.js +107 -0
  160. data/ui/views/newrelic/sample_not_found.rhtml +2 -0
  161. data/ui/views/newrelic/show_sample.rhtml +80 -0
  162. data/ui/views/newrelic/show_source.rhtml +3 -0
  163. data/ui/views/newrelic/stylesheets/style.css +484 -0
  164. data/ui/views/newrelic/threads.rhtml +52 -0
  165. metadata +248 -0
@@ -0,0 +1,18 @@
1
+
2
+ require 'new_relic/control/ruby'
3
+
4
+ class NewRelic::Control::Sinatra < NewRelic::Control::Ruby
5
+
6
+ def env
7
+ @env ||= ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
8
+ end
9
+
10
+ # This is the control used when starting up in the context of
11
+ # The New Relic Infrastructure Agent. We want to call this
12
+ # out specifically because in this context we are not monitoring
13
+ # the running process, but actually external things.
14
+ def init_config(options={})
15
+ super
16
+ end
17
+
18
+ end
@@ -0,0 +1,528 @@
1
+ require 'yaml'
2
+ require 'new_relic/local_environment'
3
+ require 'singleton'
4
+ require 'erb'
5
+ require 'socket'
6
+ require 'net/https'
7
+ require 'logger'
8
+
9
+ module NewRelic
10
+
11
+ # The Control is a singleton responsible for the startup and
12
+ # initialization sequence. The initializer uses a LocalEnvironment to
13
+ # detect the framework and instantiates the framework specific
14
+ # subclass.
15
+ #
16
+ # The Control also implements some of the public API for the agent.
17
+ #
18
+ class Control
19
+
20
+ # A flag used in dev mode to indicate if profiling is available
21
+ def profiling?
22
+ @profiling
23
+ end
24
+
25
+ def profiling_available?
26
+ @profiling_available ||=
27
+ begin
28
+ require 'ruby-prof'
29
+ true
30
+ rescue LoadError; end
31
+ end
32
+ # Set the flag for capturing profiles in dev mode. If RubyProf is not
33
+ # loaded a true value is ignored.
34
+ def profiling=(val)
35
+ @profiling = profiling_available? && val && defined?(RubyProf)
36
+ end
37
+
38
+ attr_accessor :log_file
39
+ # The env is the setting used to identify which section of the newrelic.yml
40
+ # to load. This defaults to a framework specific value, such as ENV['RAILS_ENV']
41
+ # but can be overridden as long as you set it before calling #init_plugin
42
+ attr_writer :env
43
+ attr_reader :local_env
44
+
45
+ # Structs holding info for the remote server and proxy server
46
+ class Server < Struct.new :name, :port, :ip #:nodoc:
47
+ def to_s; "#{name}:#{port}"; end
48
+ end
49
+
50
+ ProxyServer = Struct.new :name, :port, :user, :password #:nodoc:
51
+
52
+ # Access the Control singleton, lazy initialized
53
+ def self.instance
54
+ @instance ||= new_instance
55
+ end
56
+
57
+ # Initialize the plugin/gem and start the agent. This does the necessary configuration based on the
58
+ # framework environment and determines whether or not to start the agent. If the
59
+ # agent is not going to be started then it loads the agent shim which has stubs
60
+ # for all the external api.
61
+ #
62
+ # This may be invoked multiple times, as long as you don't attempt to uninstall
63
+ # the agent after it has been started.
64
+ #
65
+ # If the plugin is initialized and it determines that the agent is not enabled, it
66
+ # will skip starting it and install the shim. But if you later call this with
67
+ # <tt>:agent_enabled => true</tt>, then it will install the real agent and start it.
68
+ #
69
+ # What determines whether the agent is launched is the result of calling agent_enabled?
70
+ # This will indicate whether the instrumentation should/will be installed. If we're
71
+ # in a mode where tracers are not installed then we should not start the agent.
72
+ #
73
+ # Subclasses are not allowed to override, but must implement init_config({}) which
74
+ # is called one or more times.
75
+ #
76
+ def init_plugin(options={})
77
+ options['app_name'] = ENV['NEWRELIC_APP_NAME'] if ENV['NEWRELIC_APP_NAME']
78
+
79
+ require 'new_relic/agent'
80
+
81
+ # Load the DJ injection now. If you do it sooner, DJ might not be loaded and
82
+ # you'll miss it.
83
+ require 'new_relic/delayed_job_injection'
84
+
85
+ # Merge the stringified options into the config as overrides:
86
+ logger_override = options.delete(:log)
87
+ environment_name = options.delete(:env) and self.env = environment_name
88
+ dispatcher = options.delete(:dispatcher) and @local_env.dispatcher = dispatcher
89
+ dispatcher_instance_id = options.delete(:dispatcher_instance_id) and @local_env.dispatcher_instance_id = dispatcher_instance_id
90
+
91
+ # Clear out the settings, if they've already been loaded. It may be that
92
+ # between calling init_plugin the first time and the second time, the env
93
+ # has been overridden
94
+ @settings = nil
95
+ settings
96
+ merge_options(options)
97
+ if logger_override
98
+ @log = logger_override
99
+ # Try to grab the log filename
100
+ @log_file = @log.instance_eval { @logdev.filename rescue nil }
101
+ end
102
+ # An artifact of earlier implementation, we put both #add_method_tracer and #trace_execution
103
+ # methods in the module methods.
104
+ Module.send :include, NewRelic::Agent::MethodTracer::ClassMethods
105
+ Module.send :include, NewRelic::Agent::MethodTracer::InstanceMethods
106
+ init_config(options)
107
+ NewRelic::Agent.agent = NewRelic::Agent::Agent.instance
108
+ if agent_enabled? && !NewRelic::Agent.instance.started?
109
+ setup_log unless logger_override
110
+ start_agent
111
+ install_instrumentation
112
+ load_samplers unless self['disable_samplers']
113
+ local_env.gather_environment_info
114
+ append_environment_info
115
+ elsif !agent_enabled?
116
+ install_shim
117
+ end
118
+ end
119
+
120
+ # Install the real agent into the Agent module, and issue the start command.
121
+ def start_agent
122
+ NewRelic::Agent.agent.start
123
+ end
124
+
125
+ def [](key)
126
+ fetch(key)
127
+ end
128
+
129
+ def settings
130
+ unless @settings
131
+ @settings = (@yaml && merge_defaults(@yaml[env])) || {}
132
+ # At the time we bind the settings, we also need to run this little piece
133
+ # of magic which allows someone to augment the id with the app name, necessary
134
+ if self['multi_homed'] && app_names.size > 0
135
+ if @local_env.dispatcher_instance_id
136
+ @local_env.dispatcher_instance_id << ":#{app_names.first}"
137
+ else
138
+ @local_env.dispatcher_instance_id = app_names.first
139
+ end
140
+ end
141
+
142
+ end
143
+ @settings
144
+ end
145
+
146
+ def []=(key, value)
147
+ settings[key] = value
148
+ end
149
+
150
+ def fetch(key, default=nil)
151
+ settings.fetch(key, default)
152
+ end
153
+ # Add your own environment value to track for change detection.
154
+ # The name and value should be stable and not vary across app processes on
155
+ # the same host.
156
+ def append_environment_info(name, value)
157
+ local_env.record_environment_info(name,value)
158
+ end
159
+
160
+ ###################################
161
+ # Agent config conveniences
162
+
163
+ def apdex_t
164
+ # Always initialized with a default
165
+ fetch('apdex_t').to_f
166
+ end
167
+ def license_key
168
+ fetch('license_key')
169
+ end
170
+ def capture_params
171
+ fetch('capture_params')
172
+ end
173
+ # True if we are sending data to the server, monitoring production
174
+ def monitor_mode?
175
+ fetch('monitor_mode', fetch('enabled'))
176
+ end
177
+ # True if we are capturing data and displaying in /newrelic
178
+ def developer_mode?
179
+ fetch('developer_mode', fetch('developer'))
180
+ end
181
+ # True if the app runs in multi-threaded mode
182
+ def multi_threaded?
183
+ fetch('multi_threaded')
184
+ end
185
+ # True if we should view files in textmate
186
+ def use_textmate?
187
+ fetch('textmate')
188
+ end
189
+ def post_size_limit
190
+ fetch('post_size_limit', 2 * 1024 * 1024)
191
+ end
192
+
193
+ def sync_startup
194
+ fetch('sync_startup', false)
195
+ end
196
+ # True if dev mode or monitor mode are enabled, and we are running
197
+ # inside a valid dispatcher like mongrel or passenger. Can be overridden
198
+ # by NEWRELIC_ENABLE env variable, monitor_daemons config option when true, or
199
+ # agent_enabled config option when true or false.
200
+ def agent_enabled?
201
+ return false if !developer_mode? && !monitor_mode?
202
+ return self['agent_enabled'].to_s =~ /true|on|yes/i if !self['agent_enabled'].nil? && self['agent_enabled'] != 'auto'
203
+ return false if ENV['NEWRELIC_ENABLE'].to_s =~ /false|off|no/i
204
+ return true if self['monitor_daemons'].to_s =~ /true|on|yes/i
205
+ return true if ENV['NEWRELIC_ENABLE'].to_s =~ /true|on|yes/i
206
+ # When in 'auto' mode the agent is enabled if there is a known
207
+ # dispatcher running
208
+ return true if @local_env.dispatcher != nil
209
+ end
210
+
211
+ def app
212
+ @local_env.framework
213
+ end
214
+ alias framework app
215
+
216
+ def dispatcher_instance_id
217
+ self['dispatcher_instance_id'] || @local_env.dispatcher_instance_id
218
+ end
219
+ def dispatcher
220
+ (self['dispatcher'] && self['dispatcher'].to_sym) || @local_env.dispatcher
221
+ end
222
+ def app_names
223
+ self['app_name'] ? self['app_name'].split(';') : []
224
+ end
225
+ def validate_seed
226
+ self['validate_seed'] || ENV['NR_VALIDATE_SEED']
227
+ end
228
+ def validate_token
229
+ self['validate_token'] || ENV['NR_VALIDATE_TOKEN']
230
+ end
231
+
232
+ def use_ssl?
233
+ @use_ssl ||= fetch('ssl', false)
234
+ end
235
+
236
+ def verify_certificate?
237
+ #this can only be on when SSL is enabled
238
+ @verify_certificate ||= ( use_ssl? ? fetch('verify_certificate', false) : false)
239
+ end
240
+
241
+ def server
242
+ @remote_server ||= server_from_host(nil)
243
+ end
244
+
245
+ def api_server
246
+ api_host = self['api_host'] || 'rpm.newrelic.com'
247
+ @api_server ||=
248
+ NewRelic::Control::Server.new \
249
+ api_host,
250
+ (self['api_port'] || self['port'] || (use_ssl? ? 443 : 80)).to_i,
251
+ nil
252
+ end
253
+
254
+ def proxy_server
255
+ @proxy_server ||=
256
+ NewRelic::Control::ProxyServer.new self['proxy_host'], self['proxy_port'], self['proxy_user'], self['proxy_pass']
257
+ end
258
+
259
+ def server_from_host(hostname=nil)
260
+ host = hostname || self['host'] || 'collector.newrelic.com'
261
+
262
+ # if the host is not an IP address, turn it into one
263
+ NewRelic::Control::Server.new host, (self['port'] || (use_ssl? ? 443 : 80)).to_i, convert_to_ip_address(host)
264
+ end
265
+
266
+ # Return the Net::HTTP with proxy configuration given the NewRelic::Control::Server object.
267
+ # Default is the collector but for api calls you need to pass api_server
268
+ #
269
+ # Experimental support for SSL verification:
270
+ # swap 'VERIFY_NONE' for 'VERIFY_PEER' line to try it out
271
+ # If verification fails, uncomment the 'http.ca_file' line
272
+ # and it will use the included certificate.
273
+ def http_connection(host = nil)
274
+ host ||= server
275
+ # Proxy returns regular HTTP if @proxy_host is nil (the default)
276
+ http_class = Net::HTTP::Proxy(proxy_server.name, proxy_server.port,
277
+ proxy_server.user, proxy_server.password)
278
+ http = http_class.new(host.ip || host.name, host.port)
279
+ log.debug("Http Connection opened to #{host.ip||host.name}:#{host.port}")
280
+ if use_ssl?
281
+ http.use_ssl = true
282
+ if verify_certificate?
283
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
284
+ http.ca_file = File.join(File.dirname(__FILE__), '..', '..', 'cert', 'cacert.pem')
285
+ else
286
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
287
+ end
288
+ end
289
+ http
290
+ end
291
+ def to_s
292
+ "Control[#{self.app}]"
293
+ end
294
+
295
+ def log
296
+ # If we try to get a log before one has been set up, return a stdout log
297
+ unless @log
298
+ l = Logger.new(STDOUT)
299
+ l.level = Logger::INFO
300
+ return l
301
+ end
302
+ @log
303
+ end
304
+
305
+ # send the given message to STDOUT so that it shows
306
+ # up in the console. This should be used for important informational messages at boot.
307
+ # The to_stdout may be implemented differently by different config subclasses.
308
+ # This will NOT print anything if tracers are not enabled
309
+ def log!(msg, level=:info)
310
+ return if @settings && !agent_enabled?
311
+ to_stdout msg
312
+ log.send level, msg if @log
313
+ end
314
+
315
+ # Install stubs to the proper location so the app code will not fail
316
+ # if the agent is not running.
317
+ def install_shim
318
+ # Once we install instrumentation, you can't undo that by installing the shim.
319
+ raise "Cannot install the Agent shim after instrumentation has already been installed!" if @instrumented
320
+ NewRelic::Agent.agent = NewRelic::Agent::ShimAgent.instance
321
+ end
322
+
323
+ # Add instrumentation. Don't call this directly. Use NewRelic::Agent#add_instrumentation.
324
+ # This will load the file synchronously if we've already loaded the default
325
+ # instrumentation.
326
+ #
327
+ def add_instrumentation pattern
328
+ if @instrumented
329
+ load_instrumentation_files pattern
330
+ else
331
+ @instrumentation_files << pattern
332
+ end
333
+ end
334
+ def install_instrumentation
335
+ return if @instrumented
336
+
337
+ @instrumented = true
338
+
339
+ # Instrumentation for the key code points inside rails for monitoring by NewRelic.
340
+ # note this file is loaded only if the newrelic agent is enabled (through config/newrelic.yml)
341
+ instrumentation_path = File.join(File.dirname(__FILE__), 'agent','instrumentation')
342
+ @instrumentation_files <<
343
+ File.join(instrumentation_path, '*.rb') <<
344
+ File.join(instrumentation_path, app.to_s, '*.rb')
345
+ @instrumentation_files.each { | pattern | load_instrumentation_files pattern }
346
+ log.debug "Finished instrumentation"
347
+ end
348
+
349
+ def load_samplers
350
+ agent = NewRelic::Agent.instance
351
+ NewRelic::Agent::Sampler.sampler_classes.each do | subclass |
352
+ begin
353
+ log.debug "#{subclass.name} not supported on this platform." and next if not subclass.supported_on_this_platform?
354
+ sampler = subclass.new
355
+ if subclass.use_harvest_sampler?
356
+ agent.stats_engine.add_harvest_sampler sampler
357
+ log.debug "Registered #{subclass.name} for harvest time sampling"
358
+ else
359
+ agent.stats_engine.add_sampler sampler
360
+ log.debug "Registered #{subclass.name} for periodic sampling"
361
+ end
362
+ rescue NewRelic::Agent::Sampler::Unsupported => e
363
+ log.info "#{subclass} sampler not available: #{e}"
364
+ rescue => e
365
+ log.error "Error registering sampler: #{e}, #{e.backtrace.join("\n")}"
366
+ end
367
+ end
368
+ end
369
+
370
+ protected
371
+
372
+ # Append framework specific environment information for uploading to
373
+ # the server for change detection. Override in subclasses
374
+ def append_environment_info; end
375
+
376
+ # Look up the ip address of the host using the pure ruby lookup
377
+ # to prevent blocking. If that fails, fall back to the regular
378
+ # IPSocket library. Return nil if we can't find the host ip
379
+ # address and don't have a good default.
380
+ def convert_to_ip_address(host)
381
+ # here we leave it as a host name since the cert verification
382
+ # needs it in host form
383
+ return host if verify_certificate?
384
+ return nil if host.nil? || host.downcase == "localhost"
385
+ # Fall back to known ip address in the common case
386
+ ip_address = '65.74.177.195' if host.downcase == 'collector.newrelic.com'
387
+ begin
388
+ ip_address = Resolv.getaddress(host)
389
+ log.info "Resolved #{host} to #{ip_address}"
390
+ rescue => e
391
+ log.warn "DNS Error caching IP address: #{e}"
392
+ log.debug e.backtrace.join("\n ")
393
+ ip_address = IPSocket::getaddress host rescue ip_address
394
+ end
395
+ ip_address
396
+ end
397
+
398
+ def merge_defaults(settings_hash)
399
+ s = {
400
+ 'host' => 'collector.newrelic.com',
401
+ 'ssl' => false,
402
+ 'log_level' => 'info',
403
+ 'apdex_t' => 1.0
404
+ }
405
+ s.merge! settings_hash if settings_hash
406
+ # monitor_daemons replaced with agent_enabled
407
+ s['agent_enabled'] = s.delete('monitor_daemons') if s['agent_enabled'].nil? && s.include?('monitor_daemons')
408
+ s
409
+ end
410
+
411
+ # Control subclasses may override this, but it can be called multiple times.
412
+ def setup_log
413
+ @log_file = "#{log_path}/#{log_file_name}"
414
+ @log = Logger.new @log_file
415
+
416
+ # change the format just for our logger
417
+
418
+ def @log.format_message(severity, timestamp, progname, msg)
419
+ "[#{timestamp.strftime("%m/%d/%y %H:%M:%S %z")} #{Socket.gethostname} (#{$$})] #{severity} : #{msg}\n"
420
+ end
421
+
422
+ # set the log level as specified in the config file
423
+ case fetch("log_level","info").downcase
424
+ when "debug" then @log.level = Logger::DEBUG
425
+ when "info" then @log.level = Logger::INFO
426
+ when "warn" then @log.level = Logger::WARN
427
+ when "error" then @log.level = Logger::ERROR
428
+ when "fatal" then @log.level = Logger::FATAL
429
+ else @log.level = Logger::INFO
430
+ end
431
+ @log
432
+ end
433
+
434
+ def to_stdout(msg)
435
+ STDOUT.puts "** [NewRelic] " + msg
436
+ end
437
+
438
+ def config_file
439
+ File.expand_path(File.join(root,"config","newrelic.yml"))
440
+ end
441
+
442
+ def log_path
443
+ @log_path ||= begin
444
+ path = self['log_file_path'] || File.join(root,'log')
445
+ unless File.directory? path
446
+ path = '.'
447
+ end
448
+ File.expand_path(path)
449
+ end
450
+ end
451
+
452
+ def log_file_name
453
+ @log_file_name ||= fetch('log_file_name', 'newrelic_agent.log')
454
+ end
455
+
456
+ # Create the concrete class for environment specific behavior:
457
+ def self.new_instance
458
+ @local_env = NewRelic::LocalEnvironment.new
459
+ if @local_env.framework == :test
460
+ require File.join(newrelic_root, "test", "config", "test_control.rb")
461
+ NewRelic::Control::Test.new @local_env
462
+ else
463
+ begin
464
+ require "new_relic/control/#{@local_env.framework}.rb"
465
+ rescue LoadError
466
+ end
467
+ NewRelic::Control.const_get(@local_env.framework.to_s.capitalize).new @local_env
468
+ end
469
+ end
470
+
471
+ def initialize local_env
472
+ @local_env = local_env
473
+ @instrumentation_files = []
474
+ newrelic_file = config_file
475
+ # Next two are for populating the newrelic.yml via erb binding, necessary
476
+ # when using the default newrelic.yml file
477
+ generated_for_user = ''
478
+ license_key=''
479
+ if !File.exists?(config_file)
480
+ log! "Cannot find newrelic.yml file at #{config_file}."
481
+ @yaml = {}
482
+ else
483
+ @yaml = YAML.load(ERB.new(File.read(config_file)).result(binding))
484
+ end
485
+ rescue ScriptError, StandardError => e
486
+ puts e
487
+ puts e.backtrace.join("\n")
488
+ raise "Error reading newrelic.yml file: #{e}"
489
+ end
490
+
491
+ # The root directory for the plugin or gem
492
+ def self.newrelic_root
493
+ File.expand_path(File.join(File.dirname(__FILE__),"..",".."))
494
+ end
495
+ def newrelic_root
496
+ self.class.newrelic_root
497
+ end
498
+
499
+ # Merge the given options into the config options.
500
+ # They might be a nested hash
501
+ def merge_options(options, hash=self)
502
+ options.each do |key, val |
503
+ case
504
+ when key == :config then next
505
+ when val.is_a?(Hash)
506
+ merge_options(val, hash[key.to_s] ||= {})
507
+ when val.nil?
508
+ hash.delete(key.to_s)
509
+ else
510
+ hash[key.to_s] = val
511
+ end
512
+ end
513
+ end
514
+
515
+ def load_instrumentation_files pattern
516
+ Dir.glob(pattern) do |file|
517
+ begin
518
+ log.debug "Processing instrumentation file '#{file}'"
519
+ require file
520
+ rescue => e
521
+ log.error "Error loading instrumentation file '#{file}': #{e}"
522
+ log.debug e.backtrace.join("\n")
523
+ end
524
+ end
525
+ end
526
+
527
+ end
528
+ end