- PEP8 cleaning

- add try/catch exception for most frequent cases
 - catch key_value errors
 - catch socket error for carbon connection
 - catch for multiple exception in multigraph
 - catch exception for hello string read
This commit is contained in:
Zdenek Pizl 2014-02-04 20:07:15 +01:00
parent bb7dd53ed0
commit 25eab12604

View File

@ -15,6 +15,7 @@ RE_LEFTRIGHT = re.compile(r"^(?P<left>\S+)\s+(?P<right>\S+)$")
## TODO: Catch keyboard interrupt properly and die when requested ## TODO: Catch keyboard interrupt properly and die when requested
class Munin(): class Munin():
"""Munin host object with querying getter functions.""" """Munin host object with querying getter functions."""
def __init__(self, hostname, port=4949, args=None): def __init__(self, hostname, port=4949, args=None):
@ -22,6 +23,9 @@ class Munin():
self.port = port self.port = port
self.args = args self.args = args
self.displayname = self.hostname.split(".")[0] self.displayname = self.hostname.split(".")[0]
self._sock = None
self._conn = None
self.hello_string = None
if self.args.displayname: if self.args.displayname:
self.displayname = self.args.displayname self.displayname = self.args.displayname
@ -39,15 +43,18 @@ class Munin():
def connect(self): def connect(self):
"""Initial connection to Munin host.""" """Initial connection to Munin host."""
try: try:
self._sock = socket.create_connection((self.hostname, self.port), self._sock = socket.create_connection((self.hostname, self.port), 10)
10)
except socket.error: except socket.error:
logging.exception("Unable to connect to Munin host %s, port: %s", logging.exception("Unable to connect to Munin host %s, port: %s",
self.hostname, self.port) self.hostname, self.port)
sys.exit(1) sys.exit(1)
self._conn = self._sock.makefile() try:
self.hello_string = self._readline() self._conn = self._sock.makefile()
self.hello_string = self._readline()
except socket.error:
logging.exception("Unable to communicate to Munin host %s, port: %s",
self.hostname, self.port)
def close_connection(self): def close_connection(self):
"""Close connection to Munin host.""" """Close connection to Munin host."""
@ -73,7 +80,7 @@ class Munin():
def fetch(self, plugin): def fetch(self, plugin):
"""Fetch plugin's data fields from Munin.""" """Fetch plugin's data fields from Munin."""
self._sock.sendall("fetch %s\n" % plugin) self._sock.sendall("fetch %s\n" % plugin)
response = { None: {} } response = {None: {}}
multigraph = None multigraph = None
multigraph_prefix = "" multigraph_prefix = ""
for current_line in self._iterline(): for current_line in self._iterline():
@ -83,9 +90,12 @@ class Munin():
response[multigraph] = {} response[multigraph] = {}
continue continue
# Some munin plugins have more than one space between key and value. # Some munin plugins have more than one space between key and value.
full_key_name, key_value = RE_LEFTRIGHT.search(current_line).group(1, 2) try:
key_name = multigraph_prefix + full_key_name.split(".")[0] full_key_name, key_value = RE_LEFTRIGHT.search(current_line).group(1, 2)
response[multigraph][key_name] = key_value key_name = multigraph_prefix + full_key_name.split(".")[0]
response[multigraph][key_name] = key_value
except (KeyError, AttributeError):
logging.info("plugin multi_graph %s returns invalid data for host %s\n ", multigraph, self.hostname)
return response return response
@ -100,7 +110,7 @@ class Munin():
def get_config(self, plugin): def get_config(self, plugin):
"""Get config values for Munin plugin.""" """Get config values for Munin plugin."""
self._sock.sendall("config %s\n" % plugin) self._sock.sendall("config %s\n" % plugin)
response = { None: {} } response = {None: {}}
multigraph = None multigraph = None
for current_line in self._iterline(): for current_line in self._iterline():
@ -127,7 +137,6 @@ class Munin():
return response return response
def process_host_stats(self): def process_host_stats(self):
"""Process Munin node data, potentially sending to Carbon.""" """Process Munin node data, potentially sending to Carbon."""
start_timestamp = time.time() start_timestamp = time.time()
@ -147,16 +156,19 @@ class Munin():
logging.debug("Plugin Data: %s", plugin_data) logging.debug("Plugin Data: %s", plugin_data)
if self.args.carbon: if self.args.carbon:
for multigraph in plugin_config: for multigraph in plugin_config:
self.send_to_carbon(epoch_timestamp, try:
current_plugin, self.send_to_carbon(epoch_timestamp,
plugin_config[multigraph], current_plugin,
plugin_data[multigraph]) plugin_config[multigraph],
plugin_data[multigraph])
except KeyError:
logging.info("plugin returns invalid data:\n plugin_config: %r host %s.",
plugin_config, self.hostname)
end_timestamp = time.time() - start_timestamp end_timestamp = time.time() - start_timestamp
self.close_connection() self.close_connection()
logging.info("Finished querying host %s (Execution Time: %.2f sec).", logging.info("Finished querying host %s (Execution Time: %.2f sec).",
self.hostname, end_timestamp) self.hostname, end_timestamp)
def send_to_carbon(self, timestamp, plugin_name, plugin_config, plugin_data): def send_to_carbon(self, timestamp, plugin_name, plugin_config, plugin_data):
"""Send plugin data to Carbon over Pickle format.""" """Send plugin data to Carbon over Pickle format."""
carbon_host, carbon_port = self.args.carbon.split(":") carbon_host, carbon_port = self.args.carbon.split(":")
@ -169,11 +181,14 @@ class Munin():
plugin_name, timestamp) plugin_name, timestamp)
for data_key in plugin_data: for data_key in plugin_data:
plugin_category = plugin_config["graph_category"] try:
metric = "%s%s.%s.%s.%s" % (prefix, self.displayname, plugin_category, plugin_name, data_key) plugin_category = plugin_config["graph_category"]
value = plugin_data[data_key] metric = "%s%s.%s.%s.%s" % (prefix, self.displayname, plugin_category, plugin_name, data_key)
logging.debug("Creating metric %s, value: %s", metric, value) value = plugin_data[data_key]
data_list.append((metric, (timestamp, value))) logging.debug("Creating metric %s, value: %s", metric, value)
data_list.append((metric, (timestamp, value)))
except KeyError:
logging.info("plugin returns invalid data:\n plugin_config: %r host %s.", plugin_config, self.hostname)
if self.args.noop: if self.args.noop:
logging.info("NOOP: Not sending data to Carbon") logging.info("NOOP: Not sending data to Carbon")
@ -184,11 +199,17 @@ class Munin():
payload = pickle.dumps(data_list) payload = pickle.dumps(data_list)
header = struct.pack("!L", len(payload)) header = struct.pack("!L", len(payload))
message = header + payload message = header + payload
carbon_sock = socket.create_connection((carbon_host, carbon_port), 10) try:
carbon_sock.sendall(message) carbon_sock = socket.create_connection((carbon_host, carbon_port), 10)
carbon_sock.close() carbon_sock.sendall(message)
logging.info("Finished sending plugin %s data to Carbon for host %s.", carbon_sock.close()
plugin_name, self.hostname) logging.info("Finished sending plugin %s data to Carbon for host %s.",
plugin_name, self.hostname)
except socket.error:
logging.exception("Unable to connect to Carbon on host %s, port: %s",
carbon_host, carbon_port)
sys.exit(1)
def parse_args(): def parse_args():
"""Parse command line arguments.""" """Parse command line arguments."""
@ -202,11 +223,13 @@ def parse_args():
help="Munin host to query for stats. Default: %(default)s") help="Munin host to query for stats. Default: %(default)s")
parser.add_argument("--displayname", parser.add_argument("--displayname",
default=False, default=False,
help="If defined, use this as the name to store metrics in Graphite instead of the Munin hostname.") help="If defined, use this as the name to store metrics in Graphite instead of the Munin"
" hostname.")
parser.add_argument("--interval", parser.add_argument("--interval",
type=int, type=int,
default=60, default=60,
help="Interval (seconds) between polling Munin host for statistics. If set to 0, exit after polling once. Default: %(default)s") help="Interval (seconds) between polling Munin host for statistics. If set to 0, exit after "
"polling once. Default: %(default)s")
parser.add_argument("--noop", parser.add_argument("--noop",
action="store_true", action="store_true",
help="Don't actually send Munin data to Carbon. Default: %(default)s") help="Don't actually send Munin data to Carbon. Default: %(default)s")
@ -218,7 +241,7 @@ def parse_args():
action="store", action="store",
default="servers", default="servers",
help="Prefix used on graphite target's name. Default: %(default)s") help="Prefix used on graphite target's name. Default: %(default)s")
parser.add_argument("--verbose","-v", parser.add_argument("--verbose", "-v",
choices=[1, 2, 3], choices=[1, 2, 3],
default=2, default=2,
type=int, type=int,
@ -227,16 +250,17 @@ def parse_args():
args = parser.parse_args() args = parser.parse_args()
return args return args
def main(): def main():
args = parse_args() args = parse_args()
if args.verbose == 1: if args.verbose == 1:
LOGGING_LEVEL = logging.ERROR logging_level = logging.ERROR
elif args.verbose == 3: elif args.verbose == 3:
LOGGING_LEVEL = logging.DEBUG logging_level = logging.DEBUG
else: else:
LOGGING_LEVEL = logging.INFO logging_level = logging.INFO
logging.basicConfig(format=LOGGING_FORMAT, level=LOGGING_LEVEL) logging.basicConfig(format=LOGGING_FORMAT, level=logging_level)
munin = Munin(hostname=args.host, args=args) munin = Munin(hostname=args.host, args=args)
munin.go() munin.go()