Class: Honeybadger::Agent

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Logging::Helper
Defined in:
lib/honeybadger/agent.rb

Overview

The Honeybadger agent contains all the methods for interacting with the Honeybadger service. It can be used to send notifications to multiple projects in large apps. The global agent instance (Agent.instance) should always be accessed through the Honeybadger singleton.

Context

Context is global by default, meaning agents created via Honeybadger::Agent.new will share context (added via Honeybadger.context or #context) with other agents. This also includes the Rack environment when using the Rack::ErrorNotifier middleware. To localize context for a custom agent, use the local_context: true option when initializing.

Examples:


# Standard usage:
OtherBadger = Honeybadger::Agent.new

# With local context:
OtherBadger = Honeybadger::Agent.new(local_context: true)

OtherBadger.configure do |config|
  config.api_key = 'project api key'
end

begin
  # Risky operation
rescue => e
  OtherBadger.notify(e)
end

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Agent

Returns a new instance of Agent.



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/honeybadger/agent.rb', line 60

def initialize(opts = {})
  if opts.kind_of?(Config)
    @config = opts
    opts = {}
  end

  @context = opts.delete(:context)
  local_context = opts.delete(:local_context)

  @config ||= Config.new(opts)

  if local_context
    @context ||= ContextManager.new
    @breadcrumbs = Breadcrumbs::Collector.new(config)
  else
    @breadcrumbs = nil
  end

  init_worker
end

Instance Attribute Details

#configObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



403
404
405
# File 'lib/honeybadger/agent.rb', line 403

def config
  @config
end

#events_workerObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



474
475
476
# File 'lib/honeybadger/agent.rb', line 474

def events_worker
  @events_worker
end

#workerObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



474
475
476
# File 'lib/honeybadger/agent.rb', line 474

def worker
  @worker
end

Class Method Details

.instanceObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



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

def self.instance
  @instance
end

.instance=(instance) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



56
57
58
# File 'lib/honeybadger/agent.rb', line 56

def self.instance=(instance)
  @instance = instance
end

Instance Method Details

#add_breadcrumb(message, metadata: {}, category: "custom") ⇒ Object

Appends a breadcrumb to the trace. Use this when you want to add some custom data to your breadcrumb trace in effort to help debugging. If a notice is reported to Honeybadger, all breadcrumbs within the execution path will be appended to the notice. You will be able to view the breadcrumb trace in the Honeybadger interface to see what events led up to the notice.

Examples:

Honeybadger.add_breadcrumb("Email Sent", metadata: { user: user.id, message: message })

Parameters:

  • message (String)

    The message you want to send with the breadcrumb

  • params (Hash)

    extra options for breadcrumb building

Returns:

  • self



312
313
314
315
316
317
318
319
320
321
322
# File 'lib/honeybadger/agent.rb', line 312

def add_breadcrumb(message, metadata: {}, category: "custom")
  params = Util::Sanitizer.new(max_depth: 2).sanitize({
    category: category,
    message: message,
    metadata: 
  })

  breadcrumbs.add!(Breadcrumbs::Breadcrumb.new(**params))

  self
end

#backendObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

See Also:



484
# File 'lib/honeybadger/agent.rb', line 484

def_delegators :config, :backend

#backtrace_filter {|line| ... } ⇒ Object

DEPRECATED: Callback to filter backtrace lines. One use for this is to make additional [PROJECT_ROOT] or [GEM_ROOT] substitutions, which are used by Honeybadger when grouping errors and displaying application traces.

Examples:

Honeybadger.backtrace_filter do |line|
  line.gsub(/^\/my\/unknown\/bundle\/path/, "[GEM_ROOT]")
end

Yield Parameters:

  • line (String)

    The backtrace line to modify.

Yield Returns:

  • (String)

    The new (modified) backtrace line.



463
# File 'lib/honeybadger/agent.rb', line 463

def_delegator :config, :backtrace_filter

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Direct access to the Breadcrumbs::Collector instance



286
287
288
289
290
# File 'lib/honeybadger/agent.rb', line 286

def breadcrumbs
  return @breadcrumbs if @breadcrumbs

  Thread.current[:__hb_breadcrumbs] ||= Breadcrumbs::Collector.new(config)
end

#check_in(id) ⇒ Boolean

Perform a synchronous check_in.

Examples:

Honeybadger.check_in('1MqIo1')

Parameters:

  • id (String)

    The unique check in id (e.g. ‘1MqIo1’) or the check in url.

Returns:

  • (Boolean)

    true if the check in was successful and false otherwise.



195
196
197
198
199
200
# File 'lib/honeybadger/agent.rb', line 195

def check_in(id)
  # this is to allow check ins even if a url is passed
  check_in_id = id.to_s.strip.gsub(/\/$/, '').split('/').last
  response = backend.check_in(check_in_id)
  response.success?
end

#clear!Object

Clear all transaction scoped data.



268
269
270
271
# File 'lib/honeybadger/agent.rb', line 268

def clear!
  context_manager.clear!
  breadcrumbs.clear!
end

#configure {|Config::Ruby| ... } ⇒ Object

Configure the Honeybadger agent via Ruby.

Examples:

Honeybadger.configure do |config|
  config.api_key = 'project api key'
  config.exceptions.ignore += [CustomError]
end

Yields:



415
# File 'lib/honeybadger/agent.rb', line 415

def_delegator :config, :configure

#context(context = nil) ⇒ self

Save global context for the current request.

Examples:

Honeybadger.context({my_data: 'my value'})

# Inside a Rails controller:
before_action do
  Honeybadger.context({user_id: current_user.id})
end

# Explicit conversion
class User < ActiveRecord::Base
  def to_honeybadger_context
    { user_id: id, user_email: email }
  end
end

user = User.first
Honeybadger.context(user)

# Clearing global context:
Honeybadger.context.clear!

Parameters:

  • context (Hash) (defaults to: nil)

    A Hash of data which will be sent to Honeybadger when an error occurs. If the object responds to #to_honeybadger_context, the return value of that method will be used (explicit conversion). Can include any key/value, but a few keys have a special meaning in Honeybadger.

Options Hash (context):

  • :user_id (String)

    The user ID used by Honeybadger to aggregate user data across occurrences on the error page (optional).

  • :user_email (String)

    The user email address (optional).

  • :tags (String)

    The comma-separated list of tags. When present, tags will be applied to errors with this context (optional).

Returns:

  • (self)

    so that method calls can be chained.



262
263
264
265
# File 'lib/honeybadger/agent.rb', line 262

def context(context = nil)
  context_manager.set_context(context) unless context.nil?
  self
end

#event(event_type, payload = {}) ⇒ void

This method returns an undefined value.

Sends event to events backend

Examples:

# With event type as first argument (recommended):
Honeybadger.event("user_signed_up", user_id: 123)

# With just a payload:
Honeybadger.event(event_type: "user_signed_up", user_id: 123)

Parameters:

  • event_name (String, Hash)

    a String describing the event or a Hash when the second argument is omitted.

  • payload (Hash) (defaults to: {})

    Additional data to be sent with the event as keyword arguments



385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
# File 'lib/honeybadger/agent.rb', line 385

def event(event_type, payload = {})
  init_events_worker

  ts = DateTime.now.new_offset(0).rfc3339
  merged = {ts: ts}

  if event_type.is_a?(String)
    merged.merge!(event_type: event_type)
  else
    merged.merge!(Hash(event_type))
  end

  merged.merge!(Hash(payload))

  events_worker.push(merged)
end

#exception_filterObject

DEPRECATED: Callback to ignore exceptions.

See public API documentation for Notice for available attributes.

Examples:

# Ignoring based on error message:
Honeybadger.exception_filter do |notice|
  notice.error_message =~ /sensitive data/
end

# Ignore an entire class of exceptions:
Honeybadger.exception_filter do |notice|
  notice.exception.class < MyError
end

Yield Returns:

  • (Boolean)

    true (to ignore) or false (to send).



434
# File 'lib/honeybadger/agent.rb', line 434

def_delegator :config, :exception_filter

#exception_fingerprintObject

DEPRECATED: Callback to add a custom grouping strategy for exceptions. The return value is hashed and sent to Honeybadger. Errors with the same fingerprint will be grouped.

See public API documentation for Notice for available attributes.

Examples:

Honeybadger.exception_fingerprint do |notice|
  [notice.error_class, notice.component, notice.backtrace.to_s].join(':')
end

Yield Returns:

  • (#to_s)

    The fingerprint of the error.



449
# File 'lib/honeybadger/agent.rb', line 449

def_delegator :config, :exception_fingerprint

#flush { ... } ⇒ Object, Boolean

Flushes all data from workers before returning. This is most useful in tests when using the test backend, where normally the asynchronous nature of this library could create race conditions.

Examples:

# Without a block:
it "sends a notification to Honeybadger" do
  expect {
    Honeybadger.notify(StandardError.new('test backend'))
    Honeybadger.flush
  }.to change(Honeybadger::Backend::Test.notifications[:notices], :size).by(0)
end

# With a block:
it "sends a notification to Honeybadger" do
  expect {
    Honeybadger.flush do
      49.times do
        Honeybadger.notify(StandardError.new('test backend'))
      end
    end
  }.to change(Honeybadger::Backend::Test.notifications[:notices], :size).by(49)
end

Yields:

  • An optional block to execute (exceptions will propagate after data is flushed).

Returns:

  • (Object, Boolean)

    value of block if block is given, otherwise true on success or false if Honeybadger isn’t running.



353
354
355
356
357
358
359
# File 'lib/honeybadger/agent.rb', line 353

def flush
  return true unless block_given?
  yield
ensure
  worker.flush
  events_worker&.flush
end

#get_contextHash?

Get global context for the current request.

Examples:

Honeybadger.context({my_data: 'my value'})
Honeybadger.get_context # => {my_data: 'my value'}

Returns:

  • (Hash, nil)


280
281
282
# File 'lib/honeybadger/agent.rb', line 280

def get_context
  context_manager.get_context
end

#init!(...) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

See Also:



479
# File 'lib/honeybadger/agent.rb', line 479

def_delegators :config, :init!

#notify(exception_or_opts = nil, opts = {}, **kwargs) ⇒ String, false

Sends an exception to Honeybadger. Does not report ignored exceptions by default.

Examples:

# With an exception:
begin
  fail 'oops'
rescue => exception
  Honeybadger.notify(exception, context: {
    my_data: 'value'
  }) # => '-1dfb92ae-9b01-42e9-9c13-31205b70744a'
end

# Custom notification:
Honeybadger.notify('Something went wrong.',
  error_class: 'MyClass',
  context: {my_data: 'value'}
) # => '06220c5a-b471-41e5-baeb-de247da45a56'

Parameters:

  • exception_or_opts (Exception, Hash, Object) (defaults to: nil)

    An Exception object, or a Hash of options which is used to build the notice. All other types of objects will be converted to a String and used as the :error_message.

  • opts (Hash) (defaults to: {})

    The options Hash when the first argument is an Exception.

  • kwargs (Hash)

    options as keyword args.

Options Hash (opts):

  • :error_message (String)

    The error message.

  • :error_class (String) — default: 'Notice'

    The class name of the error.

  • :backtrace (Array)

    The backtrace of the error (optional).

  • :fingerprint (String)

    The grouping fingerprint of the exception (optional).

  • :force (Boolean) — default: false

    Always report the exception when true, even when ignored (optional).

  • :sync (Boolean) — default: false

    Send data synchronously (skips the worker) (optional).

  • :tags (String)

    The comma-separated list of tags (optional).

  • :context (Hash)

    The context to associate with the exception (optional).

  • :controller (String)

    The controller name (such as a Rails controller) (optional).

  • :action (String)

    The action name (such as a Rails controller action) (optional).

  • :parameters (Hash)

    The HTTP request paramaters (optional).

  • :session (Hash)

    The HTTP request session (optional).

  • :url (String)

    The HTTP request URL (optional).

  • :cause (Exception)

    The cause for this error (optional).

Returns:

  • (String)

    UUID reference to the notice within Honeybadger.

  • (false)

    when ignored.



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
# File 'lib/honeybadger/agent.rb', line 123

def notify(exception_or_opts = nil, opts = {}, **kwargs)
  opts = opts.dup
  opts.merge!(kwargs)

  if exception_or_opts.is_a?(Exception)
    already_reported_notice_id = exception_or_opts.instance_variable_get(:@__hb_notice_id)
    return already_reported_notice_id if already_reported_notice_id
    opts[:exception] = exception_or_opts
  elsif exception_or_opts.respond_to?(:to_hash)
    opts.merge!(exception_or_opts.to_hash)
  elsif !exception_or_opts.nil?
    opts[:error_message] = exception_or_opts.to_s
  end

  validate_notify_opts!(opts)

  add_breadcrumb(
    "Honeybadger Notice",
    metadata: opts,
    category: "notice"
  ) if config[:'breadcrumbs.enabled']

  opts[:rack_env] ||= context_manager.get_rack_env
  opts[:global_context] ||= context_manager.get_context
  opts[:breadcrumbs] ||= breadcrumbs.dup

  notice = Notice.new(config, opts)

  config.before_notify_hooks.each do |hook|
    break if notice.halted?
    with_error_handling { hook.call(notice) }
  end

  unless notice.api_key =~ NOT_BLANK
    error { sprintf('Unable to send error report: API key is missing. id=%s', notice.id) }
    return false
  end

  if !opts[:force] && notice.ignore?
    debug { sprintf('ignore notice feature=notices id=%s', notice.id) }
    return false
  end

  if notice.halted?
    debug { 'halted notice feature=notices' }
    return false
  end

  info { sprintf('Reporting error id=%s', notice.id) }

  if opts[:sync] || config[:sync]
    send_now(notice)
  else
    push(notice)
  end

  if exception_or_opts.is_a?(Exception)
    exception_or_opts.instance_variable_set(:@__hb_notice_id, notice.id) unless exception_or_opts.frozen?
  end

  notice.id
end

#stop(force = false) ⇒ Object

Stops the Honeybadger service.

Examples:

Honeybadger.stop # => nil


365
366
367
368
369
# File 'lib/honeybadger/agent.rb', line 365

def stop(force = false)
  worker.shutdown(force)
  events_worker&.shutdown(force)
  true
end

#track_deployment(environment: nil, revision: nil, local_username: nil, repository: nil) ⇒ Boolean

Track a new deployment

Examples:

Honeybadger.track_deployment(revision: 'be2ceb6')

Parameters:

  • :environment (String)

    The environment name. Defaults to the current configured environment.

  • :revision (String)

    The VCS revision being deployed. Defaults to the currently configured revision.

  • :local_username (String)

    The name of the user who performed the deploy.

  • :repository (String)

    The base URL of the VCS repository. It should be HTTPS-style.

Returns:

  • (Boolean)

    true if the deployment was successfully tracked and false otherwise.



214
215
216
217
218
219
220
221
222
223
# File 'lib/honeybadger/agent.rb', line 214

def track_deployment(environment: nil, revision: nil, local_username: nil, repository: nil)
  opts = {
    environment: environment || config[:env],
    revision: revision || config[:revision],
    local_username: local_username,
    repository: repository
  }
  response = backend.track_deployment(opts)
  response.success?
end

#with_rack_env(rack_env, &block) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



466
467
468
469
470
471
# File 'lib/honeybadger/agent.rb', line 466

def with_rack_env(rack_env, &block)
  context_manager.set_rack_env(rack_env)
  yield
ensure
  context_manager.set_rack_env(nil)
end