Created
November 19, 2015 07:27
-
-
Save viviandarkbloom/9198e2908c5a4d180e1c to your computer and use it in GitHub Desktop.
zookeeper mntr metrics to graphite - only sends numeric values; relies on nventory fqdns
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import os | |
import sys | |
import socket | |
import logging | |
import random | |
import re | |
import subprocess | |
import telnetlib | |
import time | |
import argparse | |
from StringIO import StringIO | |
class ZooKeeperServer(object): | |
def __init__(self, host='localhost', port='2181', timeout=1): | |
self._address = (host, int(port)) | |
self._timeout = timeout | |
def get_stats(self): | |
""" Get ZooKeeper server stats as a map """ | |
data = self._send_cmd('mntr') | |
if data: | |
return self._parse(data) | |
else: | |
data = self._send_cmd('stat') | |
return self._parse_stat(data) | |
def _create_socket(self): | |
return socket.socket() | |
def _send_cmd(self, cmd): | |
""" Send a 4letter word command to the server """ | |
s = self._create_socket() | |
s.settimeout(self._timeout) | |
s.connect(self._address) | |
s.send(cmd) | |
data = s.recv(2048) | |
s.close() | |
return data | |
def _parse_line(self, line): | |
try: | |
key, value = map(str.strip, line.split('\t')) | |
except ValueError: | |
raise ValueError('Found invalid line: %s' % line) | |
if not key: | |
raise ValueError('The key is mandatory and should not be empty') | |
try: | |
value = int(value) | |
except (TypeError, ValueError): | |
pass | |
return key, value | |
def _parse(self, data): | |
""" Parse the output from the 'mntr' 4letter word command """ | |
h = StringIO(data) | |
result = {} | |
for line in h.readlines(): | |
try: | |
key, value = self._parse_line(line) | |
result[key] = value | |
except ValueError: | |
pass # ignore broken lines | |
return result | |
def get_cluster_stats(): | |
""" Get stats for all the servers in the cluster """ | |
stats = {} | |
host = "127.0.0.1" | |
port = "2181" | |
try: | |
zk = ZooKeeperServer(host, port) | |
stats["%s:%s" % (host, port)] = zk.get_stats() | |
except socket.error, e: | |
# ignore because the cluster can still work even | |
# if some servers fail completely | |
# this error should be also visible in a variable | |
# exposed by the server in the statistics | |
logging.info('unable to connect to server '\ | |
'"%s" on port "%s"' % (host, port)) | |
return stats | |
def write_to_graphite(g_host, g_port, message): | |
"""Write text based data to an open tcp port""" | |
graphite = telnetlib.Telnet(g_host, g_port) | |
graphite.write(message + "\n") | |
graphite.close() | |
def main(): | |
parser = argparse.ArgumentParser() | |
parser.add_argument('graphite_host', | |
help='name of graphite server' ) | |
args = parser.parse_args() | |
host = "127.0.0.1" | |
port = "2181" | |
graphite_host = args.graphite_host | |
fqdncommand = "facter fqdn" | |
getfqdn = subprocess.Popen(fqdncommand, stdout=subprocess.PIPE, shell=True) | |
fqdn, err = getfqdn.communicate() | |
my_host = fqdn.replace('.', '_').rstrip() | |
my_class = fqdn[7:10] | |
TIMESTAMP = int(time.time()) | |
cluster_stats = get_cluster_stats() | |
for server, stats in cluster_stats.items(): | |
for key, value in stats.items(): | |
metric_path = "%s.%s.ZK_mntr.%s" % (my_class, my_host, key) | |
if type(value) is int: | |
line = "servers.%s %s %s" % (metric_path, value, TIMESTAMP) | |
random.seed(my_host) | |
sleep = random.randint(0, 40) | |
logging.debug("Sleeping for %i seconds", sleep) | |
logging.debug("Message : \n%s", line) | |
write_to_graphite(graphite_host, 2003, line) | |
print line | |
else: | |
pass | |
logging.debug("Line : %s", line) | |
if __name__ == '__main__': | |
sys.exit(main()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment