Repository URL to install this package:
|
Version:
0.6.0 ▾
|
module Skylight
module Normalizers
module Moped
class Query < Normalizer
register "query.moped"
CAT = "db.mongo.query".freeze
def normalize(trace, name, payload)
# payload: { prefix: " MOPED: #{address.resolved}", ops: operations }
# We can sometimes have multiple operations. However, it seems like this only happens when doing things
# like an insert, followed by a get last error, so we can probably ignore all but the first.
operation = payload[:ops] ? payload[:ops].first : nil
type = operation && operation.class.to_s =~ /^Moped::Protocol::(.+)$/ ? $1 : nil
case type
when "Query" then normalize_query(operation)
when "GetMore" then normalize_get_more(operation)
when "Insert" then normalize_insert(operation)
when "Update" then normalize_update(operation)
when "Delete" then normalize_delete(operation)
else :skip
end
end
private
def normalize_query(operation)
title = normalize_title("QUERY", operation)
hash, binds = extract_binds(operation.selector)
description = hash.to_json
annotations = build_annotations(operation)
annotations[:skip] = operation.skip
if operation.fields
annotations[:fields] = operation.fields.select{|k,v| v == 1 }.keys.map(&:to_s)
end
annotations[:binds] = binds unless binds.empty?
[CAT, title, description, annotations]
end
def normalize_get_more(operation)
title = normalize_title("GET_MORE", operation)
annotations = build_annotations(operation)
annotations[:limit] = operation.limit
[CAT, title, nil, annotations]
end
def normalize_insert(operation)
title = normalize_title("INSERT", operation)
annotations = build_annotations(operation)
annotations[:count] = operation.documents.count
[CAT, title, nil, annotations]
end
def normalize_update(operation)
title = normalize_title("UPDATE", operation)
selector_hash, selector_binds = extract_binds(operation.selector)
update_hash, update_binds = extract_binds(operation.update)
description = { selector: selector_hash, update: update_hash }.to_json
annotations = build_annotations(operation)
binds = {}
binds[:selector] = selector_binds unless selector_binds.empty?
binds[:update] = update_binds unless update_binds.empty?
annotations[:binds] = binds unless binds.empty?
[CAT, title, description, annotations]
end
def normalize_delete(operation)
title = normalize_title("DELETE", operation)
hash, binds = extract_binds(operation.selector)
description = hash.to_json
annotations = build_annotations(operation)
annotations[:binds] = binds unless binds.empty?
[CAT, title, description, annotations]
end
def normalize_title(type, operation)
"#{type} #{operation.collection}"
end
def build_annotations(operation)
annotations = {}
if operation.respond_to?(:flags)
flags = operation.flags.map{|f| flag_name(f) }
annotations[:flags] = flags unless flags.empty?
end
annotations
end
# Some flags used by Moped don't map directly to the Mongo docs
# See http://docs.mongodb.org/meta-driver/latest/legacy/mongodb-wire-protocol/
FLAG_MAP = {
tailable: "TailableCursor",
multi: "MultiUpdate"
}
def flag_name(flag)
FLAG_MAP[flag] || flag.to_s.sub(/^[a-z\d]*/) { $&.capitalize }.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }
end
def extract_binds(hash, binds=[])
ret = {}
hash.each do |k,v|
if v.is_a?(Hash)
ret[k] = extract_binds(v, binds)[0]
else
binds << stringify(hash[k])
ret[k] = '?'
end
end
[ret, binds]
end
def stringify(value)
value.is_a?(Regexp) ? value.inspect : value.to_s
end
end
end
end
end