class Bugsnag::MongoBreadcrumbSubscriber

Subscribes to, and creates breadcrumbs from, mongo_ruby_driver events

@api private

Constants

MAX_FILTER_DEPTH
MONGO_COMMAND_KEY
MONGO_EVENT_PREFIX
MONGO_MESSAGE_PREFIX

Public Instance Methods

failed(event) click to toggle source

Listens to the ‘failed’ event, leaving a breadcrumb

@param event [Mongo::Event::Base] the mongo_ruby_driver generated event

# File lib/bugsnag/integrations/mongo.rb, line 34
def failed(event)
  leave_mongo_breadcrumb("failed", event)
end
started(event) click to toggle source

Listens to the ‘started’ event, storing the command for later usage

@param event [Mongo::Event::Base] the mongo_ruby_driver generated event

# File lib/bugsnag/integrations/mongo.rb, line 18
def started(event)
  leave_command(event)
end
succeeded(event) click to toggle source

Listens to the ‘succeeded’ event, leaving a breadcrumb

@param event [Mongo::Event::Base] the mongo_ruby_driver generated event

# File lib/bugsnag/integrations/mongo.rb, line 26
def succeeded(event)
  leave_mongo_breadcrumb("succeeded", event)
end

Private Instance Methods

event_commands() click to toggle source

Provides access to a thread-based mongo event command hash

@return [Hash] the hash of mongo event commands

# File lib/bugsnag/integrations/mongo.rb, line 123
def event_commands
  Bugsnag.configuration.request_data[MONGO_COMMAND_KEY] ||= {}
end
leave_command(event) click to toggle source

Stores the mongo command in the request data by the request_id

@param event [Mongo::Event::Base] the mongo_ruby_driver generated event

# File lib/bugsnag/integrations/mongo.rb, line 105
def leave_command(event)
  event_commands[event.request_id] = event.command
end
leave_mongo_breadcrumb(event_name, event) click to toggle source

Generates breadcrumb data from an event

@param event_name [String] the type of event @param event [Mongo::Event::Base] the mongo_ruby_driver generated event

# File lib/bugsnag/integrations/mongo.rb, line 45
def leave_mongo_breadcrumb(event_name, event)
  message = MONGO_MESSAGE_PREFIX + event_name
  meta_data = {
    :event_name => MONGO_EVENT_PREFIX + event_name,
    :command_name => event.command_name,
    :database_name => event.database_name,
    :operation_id => event.operation_id,
    :request_id => event.request_id,
    :duration => event.duration
  }
  if (command = pop_command(event.request_id))
    collection_key = event.command_name == "getMore" ? "collection" : event.command_name
    meta_data[:collection] = command[collection_key]
    unless command["filter"].nil?
      filter = sanitize_filter_hash(command["filter"])
      meta_data[:filter] = JSON.dump(filter)
    end
  end
  meta_data[:message] = event.message if defined?(event.message)

  Bugsnag.leave_breadcrumb(message, meta_data, Bugsnag::Breadcrumbs::PROCESS_BREADCRUMB_TYPE, :auto)
end
pop_command(request_id) click to toggle source

Removes and retrieves a stored command from the request data

@param request_id [String] the id of the mongo_ruby_driver event

@return [Hash, nil] the requested command, or nil if not found

# File lib/bugsnag/integrations/mongo.rb, line 115
def pop_command(request_id)
  event_commands.delete(request_id)
end
sanitize_filter_hash(filter_hash, depth = 0) click to toggle source

Removes values from filter hashes, replacing them with ‘?’

@param filter_hash [Hash] the filter hash for the mongo transaction @param depth [Integer] the current filter depth

@return [Hash] the filtered hash

# File lib/bugsnag/integrations/mongo.rb, line 75
def sanitize_filter_hash(filter_hash, depth = 0)
  filter_hash.each_with_object({}) do |(key, value), output|
    output[key] = sanitize_filter_value(value, depth)
  end
end
sanitize_filter_value(value, depth) click to toggle source

Transforms a value element into a useful, redacted, version

@param value [Object] the filter value @param depth [Integer] the current filter depth

@return [Array, Hash, String] the sanitized value

# File lib/bugsnag/integrations/mongo.rb, line 88
def sanitize_filter_value(value, depth)
  depth += 1
  if depth >= MAX_FILTER_DEPTH
    '[MAX_FILTER_DEPTH_REACHED]'
  elsif value.is_a?(Array)
    value.map { |array_value| sanitize_filter_value(array_value, depth) }
  elsif value.is_a?(Hash)
    sanitize_filter_hash(value, depth)
  else
    '?'
  end
end