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 +13 -0
- data/README.md +71 -0
- data/bin/metricsgeek +52 -0
- data/lib/metrics_downloader.rb +48 -0
- data/lib/metrics_parser.rb +41 -0
- data/lib/metricsgeek.rb +2 -0
- metadata +59 -0
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
|
data/lib/metricsgeek.rb
ADDED
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: []
|