#!/usr/bin/env ruby require 'json' require 'optparse' require 'isna' options = {} options[:count] = 10 options[:errors] = false OptionParser.new do |opts| opts.banner = "Usage: #{$0} [OPTIONS]" opts.on('-k', '--keys [KEYS]', 'List of keys to parse from json separated by :.') do |value| unless value $stderr.puts "Please provide valid --keys got: #{value.inspect}" STDIN.each_line {} exit 1 end options[:keys] = value.split(':') end opts.on('-c', '--count [NUMBER]', 'Number of top N items to show.') do |value| options[:count] = value.to_i end opts.on('-e', '--errors', 'If we should report errors.') do |value| options[:errors] = value end end.parse! required_options = [] required_options.each do |option| unless options[option] $stderr.puts "Can not run #{option.to_s} was not given." exit 1 end end map = {} STDIN.each_line do |line| begin object = JSON.parse(line) unless options[:keys] options[:keys] == object.keys end object.each do |k, v| if options[:keys] next unless options[:keys].include?(k) end submap = map[k] ||= {} submap[v] ||= 0 submap[v] += 1 end rescue => error if options[:errors] $stderr.puts error.message end end end def print_value(result, total) percentage = "%2.2f" % (result[:incidents] / total.to_f * 100) h_percentage = (percentage.to_s + '%').rjust(6, ' ').to_ansi.yellow.to_s value = result[:incidents].to_s.rjust(10, ' ').to_ansi.green.to_s key = result[:label] puts "%s %s %s" % [value, h_percentage, key] end class GroupObject attr_accessor :category attr_accessor :results def initialize(category) @category = category @results = [] end def add_result(label, incidents) @results.push({ :label => label, :incidents => incidents }) end def total results.sum do |result| result[:incidents] end end end def get_group_objects(map) group_objects = [] map.each do |category, hash| group_object = GroupObject.new(category) hash.each do |k, v| group_object.add_result(k, v) end group_objects.push(group_object) end group_objects.sort do |a, b| a.category <=> b.category end end def print_map(map, sample) get_group_objects(map).each do |group_object| puts "\n#{group_object.category.to_s.to_ansi.cyan.to_s} (#{group_object.total})" group_object.results.sort do |a, b| a[:incidents] <=> b[:incidents] end.reverse.first(sample).each do |result| print_value(result, group_object.total) end end end print_map(map, options[:count])