ok
Direktori : /proc/self/root/lib/fm-agent/plugins/ |
Current File : //proc/self/root/lib/fm-agent/plugins/redis.py |
import agent_util import csv import sys from agent_util import float import re if sys.version[0] == "3": from io import StringIO else: from StringIO import StringIO def execute_query(config, query): cmd = agent_util.which("redis-cli") if config.get("hostname"): cmd += " -h %s" % config["hostname"] if config.get("password"): cmd += " -a '%s'" % config["password"] if config.get("port", None) is not None: cmd += " -p {}".format(config["port"]) cmd += " %s" % query status, output = agent_util.execute_command( cmd, cache_timeout=agent_util.DEFAULT_CACHE_TIMEOUT ) if status != 0: raise Exception(output) output = StringIO(output) parsed_output = list(csv.reader(output, delimiter="\t")) output_dict = {} for item in parsed_output: if len(item): a = next(csv.reader([item[0]], delimiter=":", quotechar="'")) if len(a) == 2: output_dict[a[0]] = a[1] return output_dict def execute_simple_query(config, query, db=None): "Make a call to Redis CLI that returns a single value" cmd = agent_util.which("redis-cli") if config.get("hostname"): cmd += " -h %s" % config["hostname"] if config.get("password"): cmd += " -a '%s'" % config["password"] if config.get("port", None) is not None: cmd += " -p {}".format(config["port"]) if db: cmd += " -n '%s'" % db cmd += " --csv %s" % query status, output = agent_util.execute_command( cmd, cache_timeout=agent_util.DEFAULT_CACHE_TIMEOUT ) if status != 0: raise Exception(output) try: value = float(output.strip()) except: value = None return value class RedisPlugin(agent_util.Plugin): textkey = "redis" label = "Redis" @classmethod def get_metadata(self, config): status = agent_util.SUPPORTED msg = None # check if redis is even installed installed = agent_util.which("redis-cli") and ( config or agent_util.which("redis-server") ) if not installed: status = agent_util.UNSUPPORTED if config.get("from_docker"): msg = "Please install the redis-cli on the docker host" self.log.info(msg) else: self.log.info("redis binary not found") msg = "redis binary not found" return {} if status == agent_util.SUPPORTED: try: output = execute_query(config, "ping") except: self.log.exception("error running redis query") status = agent_util.MISCONFIGURED msg = "Unable to connect to redis server, please check your Redis connection settings in the agent config file." # Get the databases with current key entries output = execute_query(config, "info keyspace") options = ["Total"] options += output.keys() data = { # Server "server.uptime_in_seconds": { "label": "Uptime in seconds", "options": None, "status": status, "error_message": msg, }, # Memory "memory.used_memory": { "label": "Used memory", "options": None, "status": status, "error_message": msg, }, "memory.used_memory_rss": { "label": "Used memory rss", "options": None, "status": status, "error_message": msg, }, "memory.used_memory_peak": { "label": "Used memory peak", "options": None, "status": status, "error_message": msg, }, # Clients "clients.connected_clients": { "label": "Connected clients", "options": None, "status": status, "error_message": msg, }, "clients.blocked_clients": { "label": "Blocked clients", "options": None, "status": status, "error_message": msg, }, # Replication "replication.connected_slaves": { "label": "Connected slaves", "options": None, "status": status, "error_message": msg, }, "replication.role": { "label": "Replication: role (master=1, slave=0)", "options": None, "status": status, "error_message": msg, }, # Persistence "persistence.rdb_changes_since_last_save": { "label": "Changes since last save", "options": None, "status": status, "error_message": msg, }, "persistence.rdb_bgsave_in_progress": { "label": "Background save in progress", "options": None, "status": status, "error_message": msg, }, # Stats "stats.total_commands_processed": { "label": "Total commands processed", "options": None, "status": status, "error_message": msg, "unit": "processed/s", }, "stats.expired_keys": { "label": "Expired keys", "options": None, "status": status, "error_message": msg, }, "stats.evicted_keys": { "label": "Evicted keys", "options": None, "status": status, "error_message": msg, "unit": "evictions/s", }, "stats.keyspace_hits": { "label": "Keyspace hits", "options": None, "status": status, "error_message": msg, "unit": "hits/s", }, "stats.keyspace_misses": { "label": "Keyspace misses", "options": None, "status": status, "error_message": msg, "unit": "misses/s", }, "stats.pubsub_channels": { "label": "Pub/sub channels", "options": None, "status": status, "error_message": msg, }, "stats.pubsub_patterns": { "label": "Pub/sub patterns", "options": None, "status": status, "error_message": msg, }, "stats.rejected_connections": { "label": "Rejected connections", "options": None, "error_message": msg, "status": status, }, "stats.hit_rate": { "label": "Hit rate", "options": None, "error_message": msg, "status": status, }, "data.llen": { "label": "Length of list", "options": None, "status": status, "option_string": 1, "error_message": msg, }, "data.hlen": { "label": "Count of fields in a hash", "options": None, "status": status, "option_string": 1, "error_message": msg, }, "data.dbsize": { "label": "Total keys", "options": options, "status": status, "error_message": msg, }, "data.dbsize_expiration": { "label": "Total keys with expiration", "options": options, "status": status, "error_message": msg, }, } return data @classmethod def get_metadata_docker(self, container, config): if "hostname" not in config: try: ip = agent_util.get_container_ip(container) config["hostname"] = ip except Exception: self.log.exception("get_metadata_docker error") config["from_docker"] = True return self.get_metadata(config) def check(self, textkey, data, config): result = 0 if textkey in ("data.llen", "data.hlen") and "::" in data: # Split the data to find a database. db, data = data.split("::") else: db = None if textkey == "data.llen": return execute_simple_query(config, "llen %s" % data, db=db) elif textkey == "data.hlen": return execute_simple_query(config, "hlen %s" % data, db=db) redis_info = execute_query(config, "INFO") if textkey in ("data.dbsize", "data.dbsize_expiration"): if textkey == "data.dbsize": exp = r"^keys=(\d+).*$" else: exp = r"^.*expires=(\d+).*$" if data == "Total": output = execute_query(config, "info keyspace") keys = output.keys() for key in keys: key_info = redis_info.get(key) if key_info: found = re.match(exp, key_info) result += int(found.groups()[0]) else: key_info = redis_info.get(data) if key_info: found = re.match(exp, key_info) if found: result = found.groups()[0] else: result = 0 elif textkey == "stats.hit_rate": keyspace_hits = int(redis_info["keyspace_hits"]) keyspace_miss = int(redis_info["keyspace_misses"]) if keyspace_hits + keyspace_miss != 0: result = keyspace_hits / (keyspace_hits + keyspace_miss) else: result = redis_info[textkey[textkey.rfind(".") + 1 :]] if textkey == "replication.role": if result == "master": result = 1 else: result = 0 try: result = int(result) except Exception: result = 0 if textkey: self.log.debug("%s: %d" % (textkey, result)) if textkey in ( "stats.evicted_keys", "stats.keyspace_hits", "stats.keyspace_misses", "stats.total_commands_processed", ): cache = self.get_cache_results(textkey, data) self.cache_result(textkey, data, result) if not cache: return None delta, previous = cache[0] if result < previous: return None result = (result - previous) / float(delta) return result def check_docker(self, container, textkey, data, config): if "hostname" not in config: try: ip = agent_util.get_container_ip(container) config["hostname"] = ip except Exception: self.log.exception("check_docker error") config["from_docker"] = True return self.check(textkey, data, config)