diff --git a/lib/sniffer.rb b/lib/sniffer.rb index f75fee2..df6524a 100644 --- a/lib/sniffer.rb +++ b/lib/sniffer.rb @@ -25,23 +25,64 @@ def start @done = false + lookup_magic = { 128 => 'req ', 129 => 'resp'} + cap.setfilter("port #{@port}") cap.loop do |packet| @metrics[:stats] = cap.stats - # parse key name, and size from VALUE responses - if packet.raw_data =~ /VALUE (\S+) \S+ (\S+)/ - key = $1 - bytes = $2 + key = "" + bytes = 0 + valid_parse = false + + if not packet.tcp_data.nil? - @semaphore.synchronize do - if @metrics[:calls].has_key?(key) - @metrics[:calls][key] += 1 - else - @metrics[:calls][key] = 1 + magic = packet.tcp_data[0].unpack('C')[0] + # binary protocol + if magic == 128 or magic == 129 + # 1 byte magic + magic_str = lookup_magic[magic] + # 1 byte opcode, e.g. set or get only.. for now 0 get 1 set 2 add + opcode = packet.tcp_data[1].unpack('C')[0] + # 2 byte key length reqs only... + key_length = packet.tcp_data[2,3].unpack('n')[0] + # 1 byte extra length + # 1 byte data type + # 2 byte status + # 4 byte total body length + total_body_length = packet.tcp_data[8,11].unpack('N')[0] + # 14 byte opaque + # 4 byte cas + # ---- total 24 bytes + + # only do this if our opcode is 0x01 e.g. set + if opcode == 1 and magic == 128 + key += packet.tcp_data[24..-1] + # body_length - 4 bytes gives us bytes like the ascii parser. why? cas? + bytes = total_body_length - 4 + valid_parse = true end + # ascii protocol + elsif packet.raw_data =~ /VALUE (\S+) \S+ (\S+)/ + key = $1 + bytes = $2 + valid_parse = true + end + # replace non printable by ~ + unless key.nil? + key = key.gsub(/[^[:print:]]/, '~') + end + + if valid_parse + @semaphore.synchronize do + if @metrics[:calls].has_key?(key) + @metrics[:calls][key] += 1 + else + @metrics[:calls][key] = 1 + end - @metrics[:objsize][key] = bytes.to_i + @metrics[:objsize][key] = bytes.to_i + end end end