metricsgeek 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE.md ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2013 Evan Chan
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ Easily grok and analyze your application metrics from a cluster, in real time, with this command line tool /
2
+ gem. Compatible with HTTP JSON metrics routes as exposed by Coda Hale's metrics package, Jolokia, ruby-
3
+ metrics, or any metrics package that exposes metrics via an HTTP route as JSON.
4
+
5
+ The only assumption is that the JSON consists of deeper and deeper levels of hashes.
6
+
7
+ * Get metrics in real time, no need to wait minutes for a central service to index your logs
8
+ * Easily see load and traffic imbalances across a cluster
9
+ * Select and filter metrics easily using wildcards
10
+ * Group and summarize metrics
11
+
12
+ Quick start
13
+ ===========
14
+ Install this gem:
15
+
16
+ gem install metricsgeek
17
+
18
+ To get a list of metrics keys from your servers:
19
+
20
+ metricsgeek --list_keys --from "server[1..8].abc.com"
21
+
22
+ To get two metrics, one a pattern, from your servers:
23
+
24
+ metricsgeek --select jvm.uptime,com.abc.*.latency.mean --from "server[1..8].abc.com"
25
+
26
+ Port and Route
27
+ ==============
28
+ The port defaults to 7000 and the route defaults to /metricz. Both of these can be set via the --port and
29
+ --route options.
30
+
31
+ Host selection
32
+ ==============
33
+ You can select multiple hosts to query in two ways.
34
+
35
+ First, individual hosts can be passed, comma separated, to the --from option.
36
+
37
+ Second, you can pass in a range of numbers within brackets, and this is automatically expanded to separate
38
+ hosts. For example,
39
+
40
+ --from server[1..3,5,8..11].dc
41
+
42
+ expands to
43
+
44
+ --from server1.dc,server2.dc,server3.dc,server5.dc,server8.dc,server9.dc,server10.dc,server11.dc
45
+
46
+ Metrics selection
47
+ =================
48
+ You can use the --list_keys option together with --from to list all the metrics keys available for querying.
49
+ This is done by flattening the JSON output from all the routes, with successive levels of JSON separated by
50
+ dots in the flat metric key.
51
+
52
+ The --select option takes one or more metric keys separated by commas. So,
53
+
54
+ --select jvm.uptime,my.app.*.latency
55
+
56
+ Note that you can use the * wildcard character to select multiple metrics keys, as well as [12] style
57
+ character selection.
58
+
59
+ Grouping metrics
60
+ ================
61
+ Intead of displaying metrics from every host on a separate line, you can group the metrics together from all hosts using one of four functions: sum, min, max, avg. For example, to compute the average uptime of all hosts:
62
+
63
+ metricsgeek --select jvm.uptime --from "server[1..8].dc" --group avg
64
+
65
+ Or, to sum up the POST rate from metric com.abc.webservice.posts.m1 across the cluster:
66
+
67
+ metricsgeek --select com.abc.webservice.posts.m1 --from "server[1..8].dc" --group sum
68
+
69
+ How to contribute
70
+ =================
71
+ Pull requests are welcome!
data/bin/metricsgeek ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+ require "trollop"
3
+ require "metricsgeek"
4
+
5
+ opts = Trollop::options do
6
+ opt :select, "metrics keys or key glob patterns, comma separated", :type => :string
7
+ opt :from, "host names, comma separated, may contain [1..10] ranges", :type => :string
8
+ opt :port, "port #", :default => 7000
9
+ opt :route, "JSON metrics route", :default => "metricz"
10
+ opt :list_keys, "Just list the keys"
11
+ opt :group, "Group metrics from hosts using min/max/avg/sum", :type => :string
12
+ opt :timeout, "Request timeout in seconds", :type => :int
13
+ end
14
+
15
+ class Array
16
+ def sum
17
+ self.inject(0) { |a, s| a + s }
18
+ end
19
+
20
+ def avg
21
+ self.sum * 1.0 / self.length
22
+ end
23
+ end
24
+
25
+ def format(number)
26
+ "%7.3f" % [number]
27
+ end
28
+
29
+ expanded_hosts = opts[:from].split(",").map { |expr| MetricsDownloader.expand_host_expr(expr) }.flatten
30
+ urls = MetricsDownloader.create_urls_from_host_params(expanded_hosts, opts[:port], opts[:route])
31
+ json_trees = MetricsDownloader.download_and_parse_json_from_urls(urls, opts[:timeout])
32
+
33
+ if opts[:list_keys]
34
+ MetricsParser.list_keys_for_hashes(json_trees).each { |key| puts key }
35
+ else
36
+ keys = opts[:select].split(",")
37
+ host_key_value = expanded_hosts.zip(json_trees).map do |host, json_tree|
38
+ matching_key_values = MetricsParser.glob_key_values(json_tree, keys)
39
+ matching_key_values.map do |flatkey, value|
40
+ {:host => host, :key => flatkey, :value => value}
41
+ end
42
+ end.flatten
43
+ host_key_value.group_by { |hash| hash[:key] }.each do |key, hashes|
44
+ puts "\n\nFor key: #{key}"
45
+ if opts[:group]
46
+ values = hashes.map { |h| h[:value] }
47
+ opts[:group].split(",").each { |func| puts " #{func}: #{format(values.send(func.to_sym))}" }
48
+ else
49
+ hashes.each { |h| puts " #{h[:host]}\t#{format(h[:value])}"}
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,48 @@
1
+ require "json"
2
+ require "yaml"
3
+ require "rest_client"
4
+
5
+ module MetricsDownloader
6
+ # @returns a list of parsed JSON hashes from each url
7
+ def self.download_and_parse_json_from_urls(urls, timeout = 5)
8
+ threads = urls.map do |url|
9
+ Thread.new do
10
+ Thread.current[:output] = begin
11
+ body = RestClient::Request.execute(:method => :get, :url => url,
12
+ :timeout => timeout,
13
+ :open_timeout => timeout)
14
+ JSON.parse(body)
15
+ rescue
16
+ # TODO: log the exception?
17
+ STDERR.puts "WARNING: Unable to parse JSON from #{url}"
18
+ {}
19
+ end
20
+ end
21
+ end
22
+
23
+ threads.map { |t| t.join; t[:output] }
24
+ end
25
+
26
+ # @param host_list A list of host strings, without the port, optionally with http:// prefix
27
+ # @route the string after the / for getting metrics, defaults to "metricz/"
28
+ # @returns a list of URLs from which to retrieve data
29
+ def self.create_urls_from_host_params(host_list, port, route = "metricz/")
30
+ host_list.map do |host|
31
+ host = host[7..-1] if host.start_with?("http:")
32
+ "http://#{host}:#{port}/#{route}"
33
+ end
34
+ end
35
+
36
+ # @param host_expr A host string with an embedded range [1..18] or individual numbers,
37
+ # [1..5,7,9] => 1,2,3,4,5,7,9 will be substituted
38
+ # @returns An expanded list of hosts, basically with the range expanded into numbers.
39
+ def self.expand_host_expr(host_expr)
40
+ if host_expr =~ /(\[([0-9.,]+)\])/
41
+ embedded_expr = $1
42
+ numbers = $2.split(",").map { |item| item.include?("..") ? eval(item).to_a : [item.to_i] }.flatten
43
+ numbers.map { |n| host_expr.gsub(embedded_expr, n.to_s) }
44
+ else
45
+ [host_expr]
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,41 @@
1
+ # Core functions for parsing metrics from JSON web output, such as that by Coda Hale's metrics library
2
+
3
+ module MetricsParser
4
+ # @param tree A hash tree such as that generated by JSON.parse()
5
+ # @param prefix A list of namespace strings to prefix the generated keys by
6
+ # @returns A flattened hash where the key is each level of the tree joined by '.'
7
+ def self.flatten_tree(json_tree, prefix=[])
8
+ flat_tree = {}
9
+ pairs = json_tree.each do |key, value|
10
+ newkey = (prefix + [key]).join(".")
11
+ flat_tree[newkey] = value
12
+ if value.is_a?(Hash)
13
+ flat_tree.update(MetricsParser.flatten_tree(value, prefix + [key]))
14
+ end
15
+ end
16
+ flat_tree
17
+ end
18
+
19
+ # @returns a list of sorted, flattened hash keys for the input JSON hash tree
20
+ def self.list_keys_for_hash(json_tree)
21
+ self.flatten_tree(json_tree).keys.sort
22
+ end
23
+
24
+ # @returns a set of flattened hash keys that's the union of the individual flat hash keys for each JSON blob
25
+ def self.list_keys_for_hashes(json_trees)
26
+ json_trees.map { |tree| self.flatten_tree(tree).keys }.flatten.uniq.sort
27
+ end
28
+
29
+ # @param json_tree As returned by JSON,parse()
30
+ # @param key_patterns a list of glob pattern strings for matching keys
31
+ # @returns a hash of flat_key to value for all keys matching any of the key_patterns
32
+ def self.glob_key_values(json_tree, key_patterns)
33
+ matches = {}
34
+ flat_tree = flatten_tree(json_tree)
35
+ key_patterns.each do |key_pattern|
36
+ matching_keys = flat_tree.keys.select { |key| File.fnmatch(key_pattern, key) }
37
+ matches.merge!(Hash[ matching_keys.map { |key| [key, flat_tree[key]] } ])
38
+ end
39
+ matches
40
+ end
41
+ end
@@ -0,0 +1,2 @@
1
+ require "metrics_downloader"
2
+ require "metrics_parser"
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: metricsgeek
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.5
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Evan Chan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-16 00:00:00.000000000Z
13
+ dependencies: []
14
+ description: ! 'Easily grok and analyze your application metrics from a cluster, in
15
+ real time, with this command line tool /
16
+
17
+ gem. Compatible with HTTP JSON metrics routes as exposed by Coda Hale''s metrics
18
+ package, Jolokia, ruby-
19
+
20
+ metrics, or any metrics package that exposes metrics via an HTTP route as JSON.
21
+
22
+ '
23
+ email: velvia@gmail.com
24
+ executables:
25
+ - metricsgeek
26
+ extensions: []
27
+ extra_rdoc_files: []
28
+ files:
29
+ - lib/metrics_downloader.rb
30
+ - lib/metrics_parser.rb
31
+ - lib/metricsgeek.rb
32
+ - bin/metricsgeek
33
+ - LICENSE.md
34
+ - README.md
35
+ homepage: http://github.com/velvia/metricsgeek
36
+ licenses: []
37
+ post_install_message:
38
+ rdoc_options: []
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubyforge_project:
55
+ rubygems_version: 1.8.10
56
+ signing_key:
57
+ specification_version: 3
58
+ summary: Easily grok and analyze application metrics from a cluster.
59
+ test_files: []