Class: NewRelic::Agent::ErrorCollector

Inherits:
Object
  • Object
show all
Includes:
NoticeError, CollectionHelper
Defined in:
lib/new_relic/agent/error_collector.rb

Overview

This class collects errors from the parent application, storing them until they are harvested and transmitted to the server

Defined Under Namespace

Modules: NoticeError, Shim

Constant Summary collapse

MAX_ERROR_QUEUE_LENGTH =

Maximum possible length of the queue - defaults to 20, may be made configurable in the future. This is a tradeoff between memory and data retention

20

Constants included from CollectionHelper

CollectionHelper::DEFAULT_ARRAY_TRUNCATION_SIZE, CollectionHelper::DEFAULT_TRUNCATION_SIZE

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from NoticeError

#add_to_error_queue, #blamed_metric_name, #custom_params_from_opts, #error_is_ignored?, #error_params_from_options, #exception_info, #extract_source, #extract_stack_trace, #fetch_from_options, #filtered_by_error_filter?, #filtered_error?, #increment_error_count!, #normalized_request_and_custom_params, #over_queue_limit?, #request_params_from_opts, #seen?, #sense_method, #should_exit_notice_error?, #tag_as_seen, #uri_ref_and_root

Methods included from CollectionHelper

#normalize_params, #strip_nr_from_backtrace

Constructor Details

#initializeErrorCollector

Returns a new error collector



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/new_relic/agent/error_collector.rb', line 26

def initialize
  @errors = []

  # lookup of exception class names to ignore.  Hash for fast access
  @ignore = {}
  @capture_source = Agent.config[:'error_collector.capture_source']

  initialize_ignored_errors(Agent.config[:'error_collector.ignore_errors'])
  @lock = Mutex.new

  Agent.config.register_callback(:'error_collector.enabled') do |config_enabled|
    ::NewRelic::Agent.logger.debug "Errors will #{config_enabled ? '' : 'not '}be sent to the New Relic service."
  end
  Agent.config.register_callback(:'error_collector.ignore_errors') do |ignore_errors|
    initialize_ignored_errors(ignore_errors)
  end
end

Instance Attribute Details

#errorsObject

Returns the value of attribute errors.



23
24
25
# File 'lib/new_relic/agent/error_collector.rb', line 23

def errors
  @errors
end

Instance Method Details

#enabled?Boolean

Returns:

  • (Boolean)


51
52
53
# File 'lib/new_relic/agent/error_collector.rb', line 51

def enabled?
  Agent.config[:'error_collector.enabled']
end

#harvest_errors(unsent_errors) ⇒ Object

Get the errors currently queued up. Unsent errors are left over from a previous unsuccessful attempt to send them to the server.



303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/new_relic/agent/error_collector.rb', line 303

def harvest_errors(unsent_errors)
  @lock.synchronize do
    errors = @errors
    @errors = []

    if unsent_errors && !unsent_errors.empty?
      errors = unsent_errors + errors
    end

    errors
  end
end

#ignore(errors) ⇒ Object

errors is an array of Exception Class Names



71
72
73
74
75
76
# File 'lib/new_relic/agent/error_collector.rb', line 71

def ignore(errors)
  errors.each do |error|
    @ignore[error] = true
    ::NewRelic::Agent.logger.debug("Ignoring errors of type '#{error}'")
  end
end

#ignore_error_filter(&block) ⇒ Object

Returns the error filter proc that is used to check if an error should be reported. When given a block, resets the filter to the provided block. The define_method() is used to wrap the block in a lambda so return statements don’t result in a LocalJump exception.



60
61
62
63
64
65
66
67
# File 'lib/new_relic/agent/error_collector.rb', line 60

def ignore_error_filter(&block)
  if block
    self.class.class_eval { define_method(:ignore_filter_proc, &block) }
    @ignore_filter = method(:ignore_filter_proc)
  else
    @ignore_filter
  end
end

#initialize_ignored_errors(ignore_errors) ⇒ Object



44
45
46
47
48
49
# File 'lib/new_relic/agent/error_collector.rb', line 44

def initialize_ignored_errors(ignore_errors)
  @ignore.clear
  ignore_errors = ignore_errors.split(",") if ignore_errors.is_a? String
  ignore_errors.each { |error| error.strip! }
  ignore(ignore_errors)
end

#notice_agent_error(exception) ⇒ Object

*Use sparingly for difficult to track bugs.*

Track internal agent errors for communication back to New Relic. To use, make a specific subclass of NewRelic::Agent::InternalAgentError, then pass an instance of it to this method when your problem occurs.

Limits are treated differently for these errors. We only gather one per class per harvest, disregarding (and not impacting) the app error queue limit.



281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/new_relic/agent/error_collector.rb', line 281

def notice_agent_error(exception)
  return unless exception.class < NewRelic::Agent::InternalAgentError

  # Log 'em all!
  NewRelic::Agent.logger.info(exception)

  @lock.synchronize do
    # Already seen this class once? Bail!
    return if @errors.any? { |err| err.exception_class_constant == exception.class }

    trace = exception.backtrace || caller.dup
    noticed_error = NewRelic::NoticedError.new("NewRelic/AgentError",
                                               {:stack_trace => trace},
                                               exception)
    @errors << noticed_error
  end
rescue => e
  NewRelic::Agent.logger.info("Unable to capture internal agent error due to an exception:", e)
end

#notice_error(exception, options = {}) ⇒ Object

Notice the error with the given available options:

  • :uri => The request path, minus any request params or query string.

  • :referer => The URI of the referer

  • :metric => The metric name associated with the transaction

  • :request_params => Request parameters, already filtered if necessary

  • :custom_params => Custom parameters

If anything is left over, it’s added to custom params If exception is nil, the error count is bumped and no traced error is recorded



260
261
262
263
264
265
266
267
268
269
270
# File 'lib/new_relic/agent/error_collector.rb', line 260

def notice_error(exception, options={})
  return if should_exit_notice_error?(exception)
  increment_error_count!(exception, options)
  NewRelic::Agent.instance.events.notify(:notice_error, exception, options)
  action_path     = fetch_from_options(options, :metric, "")
  exception_options = error_params_from_options(options).merge(exception_info(exception))
  add_to_error_queue(NewRelic::NoticedError.new(action_path, exception_options, exception))
  exception
rescue => e
  ::NewRelic::Agent.logger.warn("Failure when capturing error '#{exception}':", e)
end