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

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.



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

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.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

#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.



110
111
112
113
114
115
116
117
118
119
120
# File 'lib/new_relic/agent/error_collector.rb', line 110

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



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

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

#ignore_error_filter(&block) ⇒ Object



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

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



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

def notice_error(exception, options={})
  return unless @enabled
  return if @ignore[exception.class.name] 
  if @ignore_filter
    exception = @ignore_filter.call(exception)
    return if exception.nil?
  end

  NewRelic::Agent.get_stats("Errors/all").increment_count

  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.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.message}")
    else
      @errors << noticed_error
    end
  end
end