-
Notifications
You must be signed in to change notification settings - Fork 0
/
agent.rb
364 lines (329 loc) · 13.1 KB
/
agent.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
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
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
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
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
# = New Relic Agent
#
# New Relic RPM is a performance monitoring application for Ruby
# applications running in production. For more information on RPM
# please visit http://www.newrelic.com.
#
# The New Relic Agent can be installed in Rails applications to gather
# runtime performance metrics, traces, and errors for display in a
# Developer Mode UI (mapped to /newrelic in your application server)
# or for monitoring and analysis at http://rpm.newrelic.com with just
# about any Ruby application.
#
# For detailed information on configuring or customizing the RPM Agent
# please visit our {support and documentation site}[http://support.newrelic.com].
#
# == Starting the Agent as a Gem
#
# For Rails, add:
# config.gem 'newrelic_rpm'
# to your initialization sequence.
#
# For merb, do
# dependency 'newrelic_rpm'
# in the Merb config/init.rb
#
# For Sinatra, just require the +newrelic_rpm+ gem and it will
# automatically detect Sinatra and instrument all the handlers.
#
# For other frameworks, or to manage the agent manually,
# invoke NewRelic::Agent#manual_start directly.
#
# == Configuring the Agent
#
# All agent configuration is done in the <tt>newrelic.yml</tt> file.
# This file is by default read from the +config+ directory of the
# application root and is subsequently searched for in the application
# root directory, and then in a <tt>~/.newrelic</tt> directory
#
# == Using with Rack/Metal
#
# To instrument middlewares, refer to the docs in
# NewRelic::Agent::Instrumentation::Rack.
#
# == Agent API
#
# For details on the Agent API, refer to NewRelic::Agent.
#
#
# :main: lib/new_relic/agent.rb
module NewRelic
# == Agent APIs
# This module contains the public API methods for the Agent.
#
# For adding custom instrumentation to method invocations, refer to
# the docs in the class NewRelic::Agent::MethodTracer.
#
# For information on how to customize the controller
# instrumentation, or to instrument something other than Rails so
# that high level dispatcher actions or background tasks show up as
# first class operations in RPM, refer to
# NewRelic::Agent::Instrumentation::ControllerInstrumentation and
# NewRelic::Agent::Instrumentation::ControllerInstrumentation::ClassMethods.
#
# Methods in this module as well as documented methods in
# NewRelic::Agent::MethodTracer and
# NewRelic::Agent::Instrumentation::ControllerInstrumentation are
# available to applications. When the agent is not enabled the
# method implementations are stubbed into no-ops to reduce overhead.
#
# Methods and classes in other parts of the agent are not guaranteed
# to be available between releases.
#
# Refer to the online docs at support.newrelic.com to see how to
# access the data collected by custom instrumentation, or e-mail
# support at New Relic for help.
module Agent
extend self
require 'new_relic/version'
require 'new_relic/local_environment'
require 'new_relic/stats'
require 'new_relic/delayed_job_injection'
require 'new_relic/metrics'
require 'new_relic/metric_spec'
require 'new_relic/metric_data'
require 'new_relic/metric_parser'
require 'new_relic/collection_helper'
require 'new_relic/transaction_analysis'
require 'new_relic/transaction_sample'
require 'new_relic/noticed_error'
require 'new_relic/histogram'
require 'new_relic/agent/chained_call'
require 'new_relic/agent/agent'
require 'new_relic/agent/shim_agent'
require 'new_relic/agent/method_tracer'
require 'new_relic/agent/worker_loop'
require 'new_relic/agent/stats_engine'
require 'new_relic/agent/transaction_sampler'
require 'new_relic/agent/error_collector'
require 'new_relic/agent/busy_calculator'
require 'new_relic/agent/sampler'
require 'new_relic/agent/instrumentation/controller_instrumentation'
require 'new_relic/agent/samplers/cpu_sampler'
require 'new_relic/agent/samplers/memory_sampler'
require 'new_relic/agent/samplers/object_sampler'
require 'new_relic/agent/samplers/delayed_job_lock_sampler'
require 'set'
require 'thread'
require 'resolv'
require 'timeout'
# An exception that is thrown by the server if the agent license is invalid.
class LicenseException < StandardError; end
# An exception that forces an agent to stop reporting until its mongrel is restarted.
class ForceDisconnectException < StandardError; end
# An exception that forces an agent to restart.
class ForceRestartException < StandardError; end
# Used to blow out of a periodic task without logging a an error, such as for routine
# failures.
class ServerConnectionException < StandardError; end
# Used for when a transaction trace or error report has too much
# data, so we reset the queue to clear the extra-large item
class PostTooBigException < ServerConnectionException; end
# Reserved for future use. Meant to represent a problem on the server side.
class ServerError < StandardError; end
class BackgroundLoadingError < StandardError; end
@agent = nil
# The singleton Agent instance. Used internally.
def agent #:nodoc:
raise "Plugin not initialized!" if @agent.nil?
@agent
end
def agent= new_instance #:nodoc:
@agent = new_instance
end
alias instance agent #:nodoc:
# Get or create a statistics gatherer that will aggregate numerical data
# under a metric name.
#
# +metric_name+ should follow a slash separated path convention. Application
# specific metrics should begin with "Custom/".
#
# Return a NewRelic::Stats that accepts data
# via calls to add_data_point(value).
def get_stats(metric_name, use_scope=false)
@agent.stats_engine.get_stats(metric_name, use_scope)
end
alias get_stats_no_scope get_stats
# Get the logger for the agent. Available after the agent has initialized.
# This sends output to the agent log file.
def logger
NewRelic::Control.instance.log
end
# Call this to manually start the Agent in situations where the Agent does
# not auto-start.
#
# When the app environment loads, so does the Agent. However, the
# Agent will only connect to RPM if a web front-end is found. If
# you want to selectively monitor ruby processes that don't use
# web plugins, then call this method in your code and the Agent
# will fire up and start reporting to RPM.
#
# Options are passed in as overrides for values in the
# newrelic.yml, such as app_name. In addition, the option +log+
# will take a logger that will be used instead of the standard
# file logger. The setting for the newrelic.yml section to use
# (ie, RAILS_ENV) can be overridden with an :env argument.
#
def manual_start(options={})
raise unless Hash === options
NewRelic::Control.instance.init_plugin({ :agent_enabled => true, :sync_startup => true }.merge(options))
end
# Register this method as a callback for processes that fork
# jobs.
#
# Pass <tt>:force_reconnect => true</tt> to force the agent to
# reconnect to the server and start a worker loop for sending
# data.
#
# If the master/parent connects to the agent prior to forking the
# agent in the forked process will use that agent_run. Otherwise
# the forked process will establish a new connection with the
# server.
#
# Use this especially when you fork the process to run background
# jobs or other work. If you are doing this with a web dispatcher
# that forks worker processes then you will need to force the
# agent to reconnect, which it won't do by default. Passenger and
# Unicorn are already handled, nothing special needed for them.
def after_fork(options={})
agent.after_fork(options)
end
# Clear out any unsent metric data.
def reset_stats
agent.reset_stats
end
# Shutdown the agent. Call this before exiting. Sends any queued data
# and kills the background thread.
def shutdown
agent.shutdown
end
# Add instrumentation files to the agent. The argument should be
# a glob matching ruby scripts which will be executed at the time
# instrumentation is loaded. Since instrumentation is not loaded
# when the agent is not running it's better to use this method to
# register instrumentation than just loading the files directly,
# although that probably also works.
def add_instrumentation file_pattern
NewRelic::Control.instance.add_instrumentation file_pattern
end
# This method sets the block sent to this method as a sql
# obfuscator. The block will be called with a single String SQL
# statement to obfuscate. The method must return the obfuscated
# String SQL. If chaining of obfuscators is required, use type =
# :before or :after
#
# type = :before, :replace, :after
#
# Example:
#
# NewRelic::Agent.set_sql_obfuscator(:replace) do |sql|
# my_obfuscator(sql)
# end
#
def set_sql_obfuscator(type = :replace, &block)
agent.set_sql_obfuscator type, &block
end
# This method sets the state of sql recording in the transaction
# sampler feature. Within the given block, no sql will be recorded
#
# usage:
#
# NewRelic::Agent.disable_sql_recording do
# ...
# end
#
def disable_sql_recording
state = agent.set_record_sql(false)
begin
yield
ensure
agent.set_record_sql(state)
end
end
# This method disables the recording of transaction traces in the given
# block. See also #disable_all_tracing
def disable_transaction_tracing
state = agent.set_record_tt(false)
begin
yield
ensure
agent.set_record_tt(state)
end
end
# Cancel the collection of the current transaction in progress, if
# any. Only affects the transaction started on this thread once
# it has started and before it has completed.
def abort_transaction!
# The class may not be loaded if the agent is disabled
if defined? NewRelic::Agent::Instrumentation::MetricFrame
NewRelic::Agent::Instrumentation::MetricFrame.abort_transaction!
end
end
# Yield to the block without collecting any metrics or traces in
# any of the subsequent calls. If executed recursively, will keep
# track of the first entry point and turn on tracing again after
# leaving that block. This uses the thread local
# +newrelic_untrace+
def disable_all_tracing
agent.push_trace_execution_flag(false)
yield
ensure
agent.pop_trace_execution_flag
end
# Check to see if we are capturing metrics currently on this thread.
def is_execution_traced?
Thread.current[:newrelic_untraced].nil? || Thread.current[:newrelic_untraced].last != false
end
# Set a filter to be applied to errors that RPM will track. The
# block should evalute to the exception to track (which could be
# different from the original exception) or nil to ignore this
# exception.
#
# The block is yielded to with the exception to filter.
#
# Return the new block or the existing filter Proc if no block is passed.
#
def ignore_error_filter(&block)
agent.error_collector.ignore_error_filter(&block)
end
# Record the given error in RPM. It will be passed through the
# #ignore_error_filter if there is one.
#
# * <tt>exception</tt> is the exception which will be recorded
# Options:
# * <tt>:uri</tt> => The request path, minus any request params or query string.
# * <tt>:referer</tt> => The URI of the referer
# * <tt>:metric</tt> => The metric name associated with the transaction
# * <tt>:request_params</tt> => Request parameters, already filtered if necessary
# * <tt>:custom_params</tt> => Custom parameters
#
# Anything left over is treated as custom params
#
def notice_error(exception, options={})
NewRelic::Agent::Instrumentation::MetricFrame.notice_error(exception, options)
end
# Add parameters to the current transaction trace on the call stack.
#
def add_custom_parameters(params)
NewRelic::Agent::Instrumentation::MetricFrame.add_custom_parameters(params)
end
# The #add_request_parameters method is aliased to #add_custom_parameters
# and is now deprecated.
alias add_request_parameters add_custom_parameters #:nodoc:
# Yield to a block that is run with a database metric name
# context. This means the Database instrumentation will use this
# for the metric name if it does not otherwise know about a model.
# This is re-entrant.
#
# * <tt>model</tt> is the DB model class
# * <tt>method</tt> is the name of the finder method or other
# method to identify the operation with.
def with_database_metric_name(model, method, &block)
if frame = NewRelic::Agent::Instrumentation::MetricFrame.current
frame.with_database_metric_name(model, method, &block)
else
yield
end
end
end
end