class Honeybadger::Agent

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 {Honeybadger::Agent#context}) with other agents. This also includes the Rack environment when using the {Honeybadger::Rack::ErrorNotifier} middleware. To localize context for a custom agent, use the +local_context: true+ option when initializing.

@example

# 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

Attributes

config[R]

@api private

events_worker[R]

@api private

worker[R]

@api private

Public Class Methods

instance() click to toggle source

@api private

# File lib/honeybadger/agent.rb, line 51
def self.instance
  @instance
end
instance=(instance) click to toggle source

@api private

# File lib/honeybadger/agent.rb, line 56
def self.instance=(instance)
  @instance = instance
end
new(opts = {}) click to toggle source
# 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

Public Instance Methods

add_breadcrumb(message, metadata: {}, category: "custom") click to toggle source

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.

@example Honeybadger.add_breadcrumb(“Email Sent”, metadata: { user: user.id, message: message })

@param message [String] The message you want to send with the breadcrumb @param params [Hash] extra options for breadcrumb building @option params [Hash] :metadata Any metadata that you want to pass along with the breadcrumb. We only accept a hash with simple primatives as values (Strings, Numbers, Booleans & Symbols) (optional) @option params [String] :category You can provide a custom category. This affects how the breadcrumb is displayed, so we recommend that you pick a known category. (optional)

@return self

# File lib/honeybadger/agent.rb, line 314
def add_breadcrumb(message, metadata: {}, category: "custom")
  params = Util::Sanitizer.new(max_depth: 2).sanitize({
    category: category,
    message: message,
    metadata: metadata
  })

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

  self
end
breadcrumbs() click to toggle source

@api private Direct access to the Breadcrumbs::Collector instance

check_in(id) click to toggle source

Perform a synchronous check_in.

@example Honeybadger.check_in(‘1MqIo1’)

@param [String] id The unique check in id (e.g. ‘1MqIo1’) or the check in url.

@return [Boolean] true if the check in was successful and false otherwise.

# 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!() click to toggle source

Clear all transaction scoped data.

# File lib/honeybadger/agent.rb, line 270
def clear!
  context_manager.clear!
  breadcrumbs.clear!
end
context(context = nil, &block) click to toggle source

Save global context for the current request.

@example 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!

@param [Hash] context 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.

@option context [String] :user_id The user ID used by Honeybadger to aggregate user data across occurrences on the error page (optional). @option context [String] :user_email The user email address (optional). @option context [String] :tags The comma-separated list of tags. When present, tags will be applied to errors with this context (optional).

@return [Object, self] value of the block if passed, otherwise self

# File lib/honeybadger/agent.rb, line 262
def context(context = nil, &block)
  block_result = context_manager.set_context(context, &block) unless context.nil?
  return block_result if block_given?

  self
end
event(event_type, payload = {}) click to toggle source

Sends event to events backend

@example # 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)

@param event_name [String, Hash] a String describing the event or a Hash when the second argument is omitted. @param payload [Hash] Additional data to be sent with the event as keyword arguments

@return [void]

# File lib/honeybadger/agent.rb, line 387
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
flush() { || ... } click to toggle source

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.

@example # 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, :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

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

@return [Object, Boolean] value of block if block is given, otherwise true on success or false if Honeybadger isn’t running.

# File lib/honeybadger/agent.rb, line 355
def flush
  return true unless block_given?
  yield
ensure
  worker.flush
  events_worker&.flush
end
get_context() click to toggle source

Get global context for the current request.

@example Honeybadger.context({my_data: ‘my value’}) Honeybadger.get_context # => {my_data: ‘my value’}

@return [Hash, nil]

# File lib/honeybadger/agent.rb, line 282
def get_context
  context_manager.get_context
end
notify(exception_or_opts = nil, opts = {}, **kwargs) click to toggle source

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

@example # 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'

@param [Exception, Hash, Object] exception_or_opts 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. @param [Hash] opts The options Hash when the first argument is an Exception. @param [Hash] kwargs options as keyword args.

@option opts [String] :error_message The error message. @option opts [String] :error_class (‘Notice’) The class name of the error. @option opts [Array] :backtrace The backtrace of the error (optional). @option opts [String] :fingerprint The grouping fingerprint of the exception (optional). @option opts [Boolean] :force (false) Always report the exception when true, even when ignored (optional). @option opts [Boolean] :sync (false) Send data synchronously (skips the worker) (optional). @option opts [String] :tags The comma-separated list of tags (optional). @option opts [Hash] :context The context to associate with the exception (optional). @option opts [String] :controller The controller name (such as a Rails controller) (optional). @option opts [String] :action The action name (such as a Rails controller action) (optional). @option opts [Hash] :parameters The HTTP request paramaters (optional). @option opts [Hash] :session The HTTP request session (optional). @option opts [String] :url The HTTP request URL (optional). @option opts [Exception] :cause The cause for this error (optional).

@return [String] UUID reference to the notice within Honeybadger. @return [false] when ignored.

# 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) click to toggle source

Stops the Honeybadger service.

@example Honeybadger.stop # => nil

# File lib/honeybadger/agent.rb, line 367
def stop(force = false)
  worker.shutdown(force)
  events_worker&.shutdown(force)
  true
end
track_deployment(environment: nil, revision: nil, local_username: nil, repository: nil) click to toggle source

Track a new deployment

@example Honeybadger.track_deployment(revision: ‘be2ceb6’)

@param [String] :environment The environment name. Defaults to the current configured environment. @param [String] :revision The VCS revision being deployed. Defaults to the currently configured revision. @param [String] :local_username The name of the user who performed the deploy. @param [String] :repository The base URL of the VCS repository. It should be HTTPS-style.

@return [Boolean] true if the deployment was successfully tracked and false otherwise.

# 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) { || ... } click to toggle source

@api private

# File lib/honeybadger/agent.rb, line 468
def with_rack_env(rack_env, &block)
  context_manager.set_rack_env(rack_env)
  yield
ensure
  context_manager.set_rack_env(nil)
end

Private Instance Methods

context_manager() click to toggle source
# File lib/honeybadger/agent.rb, line 498
def context_manager
  return @context if @context
  ContextManager.current
end
init_events_worker() click to toggle source
# File lib/honeybadger/agent.rb, line 518
def init_events_worker
  return if @events_worker
  @events_worker = EventsWorker.new(config)
end
init_worker() click to toggle source
# File lib/honeybadger/agent.rb, line 513
def init_worker
  return if @worker
  @worker = Worker.new(config)
end
push(object) click to toggle source
# File lib/honeybadger/agent.rb, line 503
def push(object)
  worker.push(object)
  true
end
send_now(object) click to toggle source
# File lib/honeybadger/agent.rb, line 508
def send_now(object)
  worker.send_now(object)
  true
end
validate_notify_opts!(opts) click to toggle source
# File lib/honeybadger/agent.rb, line 490
def validate_notify_opts!(opts)
  return if opts.has_key?(:exception)
  return if opts.has_key?(:error_message)
  msg = sprintf('`Honeybadger.notify` was called with invalid arguments. You must pass either an Exception or options Hash containing the `:error_message` key. location=%s', caller[caller.size-1])
  raise ArgumentError.new(msg) if config.dev?
  warn(msg)
end
with_error_handling() { || ... } click to toggle source
# File lib/honeybadger/agent.rb, line 523
def with_error_handling
  yield
rescue => ex
  error { "Rescued an error in a before notify hook: #{ex.message}" }
end