Class: OneApm::Collector::ErrorCollector

Inherits:
Object
  • Object
show all
Includes:
OneApm::CollectionHelper, NoticeError
Defined in:
lib/one_apm/collector/containers/error_collector.rb

Defined Under Namespace

Modules: NoticeError, Shim

Constant Summary collapse

OA_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 OneApm::CollectionHelper

OneApm::CollectionHelper::OA_DEFAULT_ARRAY_TRUNCATION_SIZE, OneApm::CollectionHelper::OA_DEFAULT_TRUNCATION_SIZE

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from NoticeError

#add_to_error_queue, #aggregated_metric_names, #blamed_metric_name, #custom_params_from_opts, #error_is_ignored?, #error_params_from_options, #exception_info, #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, #skip_notice_error?, #tag_as_seen, #uri_ref_and_root

Methods included from OneApm::CollectionHelper

#normalize_params, #strip_oa_from_backtrace

Constructor Details

#initializeErrorCollector

Returns a new error collector



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/one_apm/collector/containers/error_collector.rb', line 21

def initialize
  @errors = []

  # lookup of exception class names to ignore.  Hash for fast access
  @ignore = {}

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

  OneApm::Manager.config.register_callback(:'error_collector.enabled') do |config_enabled|
    OneApm::Manager.logger.debug "Errors will #{config_enabled ? '' : 'not '}be sent to the OneApm service."
  end
  OneApm::Manager.config.register_callback(:'error_collector.ignore_errors') do |client_config_errors, server_config_errors|
    initialize_ignored_errors("#{client_config_errors},#{server_config_errors}")
  end
end

Instance Attribute Details

#errorsObject

Returns the value of attribute errors.



18
19
20
# File 'lib/one_apm/collector/containers/error_collector.rb', line 18

def errors
  @errors
end

Class Method Details

.ignore_error_filterObject



79
80
81
# File 'lib/one_apm/collector/containers/error_collector.rb', line 79

def self.ignore_error_filter
  @ignore_filter
end

.ignore_error_filter=(block) ⇒ Object

We store the passed block in both an ivar on the class, and implicitly within the body of the ignore_filter_proc method intentionally here. The define_method trick is needed to get around the fact that users may call ‘return’ from within their filter blocks, which would otherwise result in a LocalJumpError.

The raw block is also stored in an instance variable so that we can return it later in its original form.

This is all done at the class level in order to avoid the case where the user sets up an ignore filter on one instance of the ErrorCollector, and then that instance subsequently gets discarded during agent startup. (For example, if the agent is initially disabled, and then gets enabled via a call to start later on.)



69
70
71
72
73
74
75
76
77
# File 'lib/one_apm/collector/containers/error_collector.rb', line 69

def self.ignore_error_filter=(block)
  @ignore_filter = block
  if block
    define_method(:ignore_filter_proc, &block)
  elsif method_defined?(:ignore_filter_proc)
    undef :ignore_filter_proc
  end
  @ignore_filter
end

Instance Method Details

#disabled?Boolean

Returns:

  • (Boolean)


50
51
52
# File 'lib/one_apm/collector/containers/error_collector.rb', line 50

def disabled?
  !enabled?
end

#enabled?Boolean

Returns:

  • (Boolean)


46
47
48
# File 'lib/one_apm/collector/containers/error_collector.rb', line 46

def enabled?
  OneApm::Manager.config[:'error_collector.enabled']
end

#harvest!Object

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



335
336
337
338
339
340
341
# File 'lib/one_apm/collector/containers/error_collector.rb', line 335

def harvest!
  @lock.synchronize do
    errors = @errors
    @errors = []
    errors
  end
end

#ignore(errors) ⇒ Object

errors is an array of Exception Class Names



84
85
86
87
88
89
# File 'lib/one_apm/collector/containers/error_collector.rb', line 84

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

#initialize_ignored_errors(ignore_errors) ⇒ Object



38
39
40
41
42
43
44
# File 'lib/one_apm/collector/containers/error_collector.rb', line 38

def initialize_ignored_errors(ignore_errors)
  @ignore.clear
  ignore_errors = ignore_errors.split(",") if ignore_errors.is_a? String
  ignore_errors.map(&:strip!)
  ignore_errors.uniq!
  ignore(ignore_errors)
end

#merge!(errors) ⇒ Object



327
328
329
330
331
# File 'lib/one_apm/collector/containers/error_collector.rb', line 327

def merge!(errors)
  errors.each do |error|
    add_to_error_queue(error)
  end
end

#notice_agent_error(exception) ⇒ Object

*Use sparingly for difficult to track bugs.*

Track internal agent errors for communication back to OneApm. To use, make a specific subclass of OneApm::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.



307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
# File 'lib/one_apm/collector/containers/error_collector.rb', line 307

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

  # Log 'em all!
  OneApm::Manager.logger.info(exception)

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

    trace = exception.backtrace || caller.dup
    noticed_error = OneApm::NoticedError.new("OneApm/AgentError",
                                             {:stack_trace => trace},
                                             exception)
    @errors << noticed_error
  end
rescue => e
  OneApm::Manager.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



280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/one_apm/collector/containers/error_collector.rb', line 280

def notice_error(exception, options={})
  state = ::OneApm::TransactionState.tl_get

  return if skip_notice_error?(state, exception)
  tag_as_seen(state, exception)

  increment_error_count!(state, exception, options)
  OneApm::Manager.agent.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(OneApm::NoticedError.new(action_path, exception_options, exception))

  exception
rescue => e
  OneApm::Manager.logger.warn("Failure when capturing error '#{exception}':", e)
end

#reset!Object



343
344
345
346
347
# File 'lib/one_apm/collector/containers/error_collector.rb', line 343

def reset!
  @lock.synchronize do
    @errors = []
  end
end