Class: NewRelic::Agent::ErrorCollector

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

Defined Under Namespace

Modules: Shim

Constant Summary collapse

MAX_ERROR_QUEUE_LENGTH =
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 CollectionHelper

#normalize_params, #strip_nr_from_backtrace

Constructor Details

#initializeErrorCollector

Returns a new instance of ErrorCollector.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/new_relic/agent/error_collector.rb', line 18

def initialize
  @errors = []
  # lookup of exception class names to ignore.  Hash for fast access
  @ignore = {}
  @ignore_filter = nil

  config = NewRelic::Control.instance.fetch('error_collector', {})

  @enabled = @config_enabled = config.fetch('enabled', true)
  @capture_source = config.fetch('capture_source', true)

  ignore_errors = config.fetch('ignore_errors', "")
  ignore_errors = ignore_errors.split(",") if ignore_errors.is_a? String
  ignore_errors.each { |error| error.strip! }
  ignore(ignore_errors)
  @lock = Mutex.new
end

Instance Attribute Details

#config_enabledObject (readonly)

Returns the value of attribute config_enabled.



16
17
18
# File 'lib/new_relic/agent/error_collector.rb', line 16

def config_enabled
  @config_enabled
end

#enabledObject

Returns the value of attribute enabled.



15
16
17
# File 'lib/new_relic/agent/error_collector.rb', line 15

def enabled
  @enabled
end

Instance Method Details

#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. We first clear out all unsent errors before sending the newly queued errors.



113
114
115
116
117
118
119
120
121
122
123
# File 'lib/new_relic/agent/error_collector.rb', line 113

def harvest_errors(unsent_errors)
  if unsent_errors && !unsent_errors.empty?
    return unsent_errors
  else
    @lock.synchronize do
      errors = @errors
      @errors = []
      return errors
    end
  end
end

#ignore(errors) ⇒ Object

errors is an array of Exception Class Names



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

def ignore(errors)
  errors.each { |error| @ignore[error] = true; log.debug("Ignoring errors of type '#{error}'") }
end

#ignore_error_filter(&block) ⇒ Object



36
37
38
39
40
41
42
# File 'lib/new_relic/agent/error_collector.rb', line 36

def ignore_error_filter(&block)
  if block
    @ignore_filter = block
  else
    @ignore_filter
  end
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



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
# File 'lib/new_relic/agent/error_collector.rb', line 60

def notice_error(exception, options={})
  return unless @enabled
  return if exception && @ignore[exception.class.name]
  if @ignore_filter && exception
    exception = @ignore_filter.call(exception)
    return if exception.nil?
  end
  NewRelic::Agent.get_stats("Errors/all").increment_count
  return if exception.nil?

  data = {}
  data[:request_uri] = options.delete(:uri) || ''
  data[:request_referer] = options.delete(:referer) || ''

  action_path     = options.delete(:metric) || NewRelic::Agent.instance.stats_engine.scope_name || ''
  request_params = options.delete(:request_params)
  custom_params = options.delete(:custom_params) || {}
  # If anything else is left over, treat it like a custom param:
  custom_params.merge! options

  data[:request_params] = normalize_params(request_params) if NewRelic::Control.instance.capture_params && request_params
  data[:custom_params] = normalize_params(custom_params) unless custom_params.empty?
  data[:rails_root] = NewRelic::Control.instance.root
  data[:file_name] = exception.file_name if exception.respond_to?('file_name')
  data[:line_number] = exception.line_number if exception.respond_to?('line_number')

  if @capture_source && exception.respond_to?('source_extract')
    data[:source] = exception.source_extract
  end

  if exception.respond_to? 'original_exception'
    inside_exception = exception.original_exception
  else
    inside_exception = exception
  end

  data[:stack_trace] = (inside_exception && inside_exception.respond_to?('backtrace')) ? inside_exception.backtrace : '<no stack trace>'

  noticed_error = NewRelic::NoticedError.new(action_path, data, exception)

  @lock.synchronize do
    if @errors.length == MAX_ERROR_QUEUE_LENGTH
      log.warn("The error reporting queue has reached #{MAX_ERROR_QUEUE_LENGTH}. The error detail for this and subsequent errors will not be transmitted to RPM until the queued errors have been sent: #{exception}")
    else
      @errors << noticed_error
    end
  end
  exception
end