class Skylight::Core::Probes::Mongo::Subscriber

Constants

COMMANDS
COMMAND_NAMES

Public Class Methods

new() click to toggle source
# File lib/skylight/core/probes/mongo.rb, line 21
def initialize
  @events = {}
end

Public Instance Methods

config() click to toggle source

For logging

# File lib/skylight/core/probes/mongo.rb, line 38
def config
  # Just log to the first instrumentable's config for now.
  # FIXME: Revisit this
  if (instrumentable = Fanout.registered.first)
    if (instrumenter = instrumentable.instrumenter)
      instrumenter.config
    end
  end
end
failed(event) click to toggle source
# File lib/skylight/core/probes/mongo.rb, line 33
def failed(event)
  end_instrumentation(event)
end
started(event) click to toggle source
# File lib/skylight/core/probes/mongo.rb, line 25
def started(event)
  begin_instrumentation(event)
end
succeeded(event) click to toggle source
# File lib/skylight/core/probes/mongo.rb, line 29
def succeeded(event)
  end_instrumentation(event)
end

Private Instance Methods

add_bound(key, command, payload) click to toggle source
# File lib/skylight/core/probes/mongo.rb, line 149
def add_bound(key, command, payload)
  if (value = command[key])
    payload[key] = extract_binds(value)
  end
end
add_value(key, command, payload) click to toggle source
# File lib/skylight/core/probes/mongo.rb, line 142
def add_value(key, command, payload)
  if command.key?(key)
    value = command[key]
    payload[key] = value
  end
end
begin_instrumentation(event) click to toggle source
# File lib/skylight/core/probes/mongo.rb, line 50
def begin_instrumentation(event)
  return unless COMMANDS.include?(event.command_name.to_sym)

  command_name = COMMAND_NAMES[event.command_name] || event.command_name

  title = "#{event.database_name}.#{command_name}"

  command = event.command

  # Not sure if this will always exist
  # Delete so the description will be less redundant
  if (target = command[event.command_name])
    title << " #{target}"
  end

  payload = {}

  # Ruby Hashes are ordered based on insertion so do the most important ones first

  add_value("key".freeze, command, payload)
  add_bound("query".freeze, command, payload)
  add_bound("filter".freeze, command, payload)
  add_value("sort".freeze, command, payload)

  if event.command_name == :findandmodify
    add_bound("update".freeze, command, payload)
  end

  add_value("remove".freeze, command, payload)
  add_value("new".freeze, command, payload)

  if (updates = command["updates".freeze])
    # AFAICT the gem generally just sends one item in the updates array
    update = updates[0]
    update_payload = {}
    add_bound("q".freeze, update, update_payload)
    add_bound("u".freeze, update, update_payload)
    add_value("multi".freeze, update, update_payload)
    add_value("upsert".freeze, update, update_payload)

    payload["updates".freeze] = [update_payload]

    if updates.length > 1
      payload["updates".freeze] << "..."
    end
  end

  if (deletes = command["deletes".freeze])
    # AFAICT the gem generally just sends one item in the updates array
    delete = deletes[0]
    delete_payload = {}
    add_bound("q".freeze, delete, delete_payload)
    add_value("limit".freeze, delete, delete_payload)

    payload["deletes".freeze] = [delete_payload]

    if deletes.length > 1
      payload["deletes".freeze] << "..."
    end
  end

  if (pipeline = command["pipeline".freeze])
    payload["pipeline".freeze] = pipeline.map { |segment| extract_binds(segment) }
  end

  # We're ignoring documents from insert because they could have completely inconsistent
  # format which would make it hard to merge.

  opts = {
    category:    CAT,
    title:       title,
    description: payload.empty? ? nil : payload.to_json,
    meta:        { database: event.database_name }
  }

  @events[event.operation_id] = Skylight::Core::Fanout.instrument(opts)
rescue Exception => e
  error "failed to begin instrumentation for Mongo; msg=%s", e.message
end
end_instrumentation(event) click to toggle source
# File lib/skylight/core/probes/mongo.rb, line 130
def end_instrumentation(event)
  if (original_event = @events.delete(event.operation_id))
    meta = {}
    if event.is_a?(::Mongo::Monitoring::Event::CommandFailed)
      meta[:exception] = ["CommandFailed", event.message]
    end
    Skylight::Core::Fanout.done(original_event, meta)
  end
rescue Exception => e
  error "failed to end instrumentation for Mongo; msg=%s", e.message
end
extract_binds(hash) click to toggle source
# File lib/skylight/core/probes/mongo.rb, line 155
def extract_binds(hash)
  ret = {}

  hash.each do |k, v|
    ret[k] = v.is_a?(Hash) ? extract_binds(v) : "?".freeze
  end

  ret
end