Skip to content

Commit 183e343

Browse files
fsnipermajormoses
authored andcommitted
Added metrics-zookeeper-cluster (#12)
* Added metrics-zookeeper-cluster * Removed trailing ws * handled http redirection * Fixed spacing * Added proper url redirection following * rubocop fixes
1 parent 105d87a commit 183e343

File tree

3 files changed

+203
-0
lines changed

3 files changed

+203
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ This CHANGELOG follows the format listed at [Keep A Changelog](http://keepachang
99
### Added
1010
- check-zookeper-cluster
1111
- Ruby 2.4.1 testing
12+
- metrics-zookeeper-cluster.rb
1213

1314
## [1.1.0] - 2017-03-23
1415
- add `check-zookeeper-mode` to check if zookeeper is in the expected mode (@karthik-altiscale)

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
* check-zookeeper-mode.rb - Check if Zookeeper node is in standalone or cluster(leader or follower) mode
1919
* check-zookeeper-cluster.rb - Check if a exhibitor managed Zookeeper cluster is OK.
2020
* metrics-zookeeper.rb - Gather metrics from Zookeeper
21+
* metrics-zookeeper-cluster.rb - Gather metrics from An Exhibitor run Zookeeper cluster
2122

2223
## Usage
2324

bin/metrics-zookeeper-cluster.rb

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
#!/usr/bin/env ruby
2+
#
3+
# metrics-zookeeper.rb
4+
#
5+
# Collect ZooKeeper metrics
6+
# ===
7+
#
8+
# DESCRIPTION:
9+
# This plugin gathers metrics from an Exhibitor run ZooKeeper cluster,
10+
# based on the collectd plugin:
11+
#
12+
# https://github.com/Nextdoor/collectd_plugins/blob/master/zookeeper/zookeeper.sh
13+
#
14+
#
15+
# PLATFORMS:
16+
# Linux, BSD, Solaris
17+
#
18+
# DEPENDENCIES:
19+
# gem: sensu-plugin
20+
#
21+
# LICENSE:
22+
# Sean Clemmer sczizzo@gmail.com
23+
# Released under the same terms as Sensu (the MIT license); see LICENSE
24+
# for details.
25+
#
26+
27+
require 'sensu-plugin/metric/cli'
28+
require 'socket'
29+
require 'net/http'
30+
require 'json'
31+
32+
class ZookeeperMetrics < Sensu::Plugin::Metric::CLI::Graphite
33+
option :exhibitor,
34+
description: 'exhibitor end node for status checks',
35+
short: '-e Exhibitor status end point',
36+
long: '--exhibitor status end point',
37+
default: 'http://localhost/exhibitor/v1/cluster/status'
38+
39+
option :scheme,
40+
description: 'Metric naming scheme, text to prepend to metrics',
41+
long: '--scheme SCHEME',
42+
default: 'zookeeper'
43+
44+
def follow_url(uri_str, agent = 'curl/7.43.0', max_attempts = 10, timeout = 10)
45+
attempts = 0
46+
cookie = nil
47+
48+
until attempts >= max_attempts
49+
attempts += 1
50+
51+
url = URI.parse(uri_str)
52+
http = Net::HTTP.new(url.host, url.port)
53+
http.open_timeout = timeout
54+
http.read_timeout = timeout
55+
path = url.path
56+
path = '/' if path == ''
57+
path += '?' + url.query unless url.query.nil?
58+
59+
params = { 'User-Agent' => agent, 'Accept' => '*/*' }
60+
params['Cookie'] = cookie unless cookie.nil?
61+
request = Net::HTTP::Get.new(path, params)
62+
63+
if url.instance_of?(URI::HTTPS)
64+
http.use_ssl = true
65+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
66+
end
67+
response = http.request(request)
68+
69+
case response
70+
when Net::HTTPSuccess then
71+
break
72+
when Net::HTTPRedirection then
73+
location = response['Location']
74+
cookie = response['Set-Cookie']
75+
new_uri = URI.parse(location)
76+
uri_str = if new_uri.relative?
77+
url + location
78+
else
79+
new_uri.to_s
80+
end
81+
else
82+
raise 'Unexpected response: ' + response.inspect
83+
end
84+
85+
end
86+
raise 'Too many http redirects' if attempts == max_attempts
87+
88+
response
89+
end
90+
91+
def dotted(*args)
92+
args.join('.')
93+
end
94+
95+
def zk_command(four_letter_word, host, port)
96+
Socket.tcp(host, port) do |sock|
97+
sock.print "#{four_letter_word}\r\n"
98+
sock.close_write
99+
sock.read
100+
end
101+
end
102+
103+
def exhibitor_status
104+
response = follow_url(config[:exhibitor])
105+
JSON.parse(response.body)
106+
rescue StandardError => e
107+
[false, json, ['exhibitor status is not http 200 ' + e.message]]
108+
end
109+
110+
def run
111+
timestamp = Time.now.to_i
112+
113+
json = exhibitor_status
114+
json.each do |zk|
115+
hostname = zk['hostname']
116+
response = zk_command(:mntr, hostname, 2181)
117+
metrics = {}
118+
119+
if response =~ /^zk_avg_latency\s*(\d+)$/
120+
metrics[:zk_avg_latency] = Regexp.last_match(1).to_i
121+
end
122+
123+
if response =~ /^zk_max_latency\s*(\d+)$/
124+
metrics[:zk_max_latency] = Regexp.last_match(1).to_i
125+
end
126+
127+
if response =~ /^zk_min_latency\s*(\d+)$/
128+
metrics[:zk_min_latency] = Regexp.last_match(1).to_i
129+
end
130+
131+
if response =~ /^zk_packets_received\s*(\d+)$/
132+
metrics[:zk_packets_received] = Regexp.last_match(1).to_i
133+
end
134+
135+
if response =~ /^zk_packets_sent\s*(\d+)$/
136+
metrics[:zk_packets_sent] = Regexp.last_match(1).to_i
137+
end
138+
139+
if response =~ /^zk_num_alive_connections\s*(\d+)$/
140+
metrics[:zk_num_alive_connections] = Regexp.last_match(1).to_i
141+
end
142+
143+
if response =~ /^zk_outstanding_requests\s*(\d+)$/
144+
metrics[:zk_outstanding_requests] = Regexp.last_match(1).to_i
145+
end
146+
147+
metrics[:zk_is_leader] = if response =~ /^zk_server_state\s*leader$/
148+
1
149+
else
150+
0
151+
end
152+
153+
if response =~ /^zk_znode_count\s*(\d+)$/
154+
metrics[:zk_znode_count] = Regexp.last_match(1).to_i
155+
end
156+
157+
if response =~ /^zk_watch_count\s*(\d+)$/
158+
metrics[:zk_watch_count] = Regexp.last_match(1).to_i
159+
end
160+
161+
if response =~ /^zk_ephemerals_count\s*(\d+)$/
162+
metrics[:zk_ephemerals_count] = Regexp.last_match(1).to_i
163+
end
164+
165+
if response =~ /^zk_approximate_data_size\s*(\d+)$/
166+
metrics[:zk_approximate_data_size] = Regexp.last_match(1).to_i
167+
end
168+
169+
if response =~ /^zk_open_file_descriptor_count\s*(\d+)$/
170+
metrics[:zk_open_file_descriptor_count] = Regexp.last_match(1).to_i
171+
end
172+
173+
if response =~ /^zk_max_file_descriptor_count\s*(\d+)$/
174+
metrics[:zk_max_file_descriptor_count] = Regexp.last_match(1).to_i
175+
end
176+
177+
metrics[:zk_followers] = if response =~ /^zk_followers\s*(\d+)$/
178+
Regexp.last_match(1).to_i
179+
else
180+
0
181+
end
182+
183+
metrics[:zk_synced_followers] = if response =~ /^zk_synced_followers\s*(\d+)$/
184+
Regexp.last_match(1).to_i
185+
else
186+
0
187+
end
188+
189+
metrics[:zk_pending_syncs] = if response =~ /^zk_pending_syncs\s*(\d+)$/
190+
Regexp.last_match(1).to_i
191+
else
192+
0
193+
end
194+
195+
metrics.each do |metric, value|
196+
output dotted(config[:scheme], hostname, metric), value, timestamp
197+
end
198+
end
199+
ok
200+
end
201+
end

0 commit comments

Comments
 (0)