Commit 5f26d5cd authored by Jose Castro Leon's avatar Jose Castro Leon
Browse files

Initial commit

parents
*.pyc
*.pyo
MANIFEST
include etc/memcache-stats.conf
SPECFILE = memcache-stats.spec
all:
python setup.py sdist --dist-dir .
clean:
python setup.py clean --all
srpm: all
rpmbuild -bs --define "_sourcedir `pwd`" ${SPECFILE}
rpm: all
rpmbuild -ba --define "_sourcedir `pwd`" ${SPECFILE}
scratch:
koji build cci7-utils --nowait --scratch git+https://gitlab.cern.ch/cloud-infrastructure/memcache-stats.git#$(shell git describe)
build:
koji build cci7-utils --nowait git+https://gitlab.cern.ch/cloud-infrastructure/memcache-stats.git#$(shell git describe)
tag-qa:
koji tag-pkg cci7-utils-qa --nowait memcache-stats-$(shell git describe).el7
tag-stable:
koji tag-pkg cci7-utils-stable --nowait memcache-stats-$(shell git describe).el7
[DEFAULT]
#Exclusions of stats in memcached
exclusions=pid,libevent,rusage_user,rusage_system,version
[logging]
# Log level. Defaults to INFO
level=INFO
[flume]
# Host to use to send results to flume
# host=localhost
# Port to use to send results to flume
# port=9000
[memcache]
# Host to use to connect to retrieve memcache stats
# host=localhost
# Port to use to connect to retrieve memcache stats
# port=11211
Name: memcache-stats
Version: 0.0
Release: 1%{?dist}
Summary: Flume publisher of memcached stats
Source0: %{name}-%{version}.tar.gz
BuildArch: noarch
Group: CERN/Utilities
License: Apache License, Version 2.0
URL: https://openstack.cern.ch/
BuildRequires: python-devel
%description
Flume publisher of memcached stats
%prep
%setup -q
%build
CFLAGS="%{optflags}" %{__python} setup.py build
%install
%{__rm} -rf %{buildroot}
%{__python} setup.py install --skip-build --root %{buildroot}
install -p -D -m 755 scripts/memcache-stats %{buildroot}/usr/bin/memcache-stats
%clean
%{__rm} -rf %{buildroot}
%files
%defattr(-,root,root,-)
%{_bindir}/memcache-stats
%{python_sitelib}/*
%dir /etc/%{name}
/etc/%{name}/memcache-stats.conf
%changelog
* Tue Jun 30 2015 Jose Castro Leon <jose.castro.leon@cern.ch> 0.0-1
- Initial version of the rpm
#!/usr/bin/env python
import argparse
import ConfigParser
import datetime
import httplib
import json
import logging
import os
import re
import subprocess
import sys
import telnetlib
import time
CONF = "/etc/memcache-stats/memcache-stats.conf"
LOG = logging.getLogger(__name__)
class MemcachedStats:
_client = None
_key_regex = re.compile(ur'ITEM (.*) \[(.*); (.*)\]')
_slab_regex = re.compile(ur'STAT items:(.*):number')
_stat_regex = re.compile(ur"STAT (.*) (.*)\r")
def __init__(self, host='localhost', port='11211'):
self._host = host
self._port = port
@property
def client(self):
if self._client is None:
self._client = telnetlib.Telnet(self._host, self._port)
return self._client
def command(self, cmd):
' Write a command to telnet and return the response '
self.client.write("%s\n" % cmd)
return self.client.read_until('END')
def key_details(self, sort=True, limit=100):
' Return a list of tuples containing keys and details '
cmd = 'stats cachedump %s %s'
keys = [key for id in self.slab_ids()
for key in self._key_regex.findall(self.command(cmd % (id, limit)))]
if sort:
return sorted(keys)
else:
return keys
def keys(self, sort=True, limit=100):
return [key[0] for key in self.key_details(sort=sort, limit=limit)]
def slab_ids(self):
return self._slab_regex.findall(self.command('stats items'))
def stats(self):
' Return a dict containing memcached stats '
return dict(self._stat_regex.findall(self.command('stats')))
def send_result(stats, flume_host, flume_port, exclusions):
results = [{"headers":{'key': key, 'value_int': stats[key]}, "body":"empty"} for key in stats if key not in exclusions]
LOG.debug("Sending result to Flume (%s)" % flume_host)
try:
headers = {"Content-type": "application/json"}
server = "%s:%s" % (flume_host, flume_port)
conn = httplib.HTTPConnection(server)
conn.request("POST", "/", json.dumps(results), headers)
conn.close()
except Exception as e:
LOG.error(e)
class LoggingNullHandler(logging.Handler):
"""This is for handling logging.NullHandler."""
def emit(self, record):
pass
def set_logger(level=None, file=None):
"""Setup appropriate logger."""
if level is not None:
if file is not None:
handler = logging.FileHandler(file)
else:
handler = logging.StreamHandler()
LOG.setLevel(getattr(logging, level))
handler.setLevel(getattr(logging, level))
else:
handler = LoggingNullHandler()
format = "%(asctime)s %(process)d %(levelname)s %(message)s"
handler.setFormatter(logging.Formatter(format))
LOG.addHandler(handler)
def get_args():
"""Create argument options with default values which are fetched in
config file. And return arguments.
"""
DESC = "CLI for Memcached stats"
try:
conf_parser = ConfigParser.SafeConfigParser()
conf_parser.read(CONF)
DFLT_EXCLUSIONS = conf_parser.get("DEFAULT", "exclusions")
DFLT_LOG_LEVEL = conf_parser.get("logging", "level")
DFLT_MEMCACHE_HOST = conf_parser.get("memcache", "host")
DFLT_MEMCACHE_PORT = conf_parser.get("memcache", "port")
DFLT_FLUME_HOST = conf_parser.get("flume", "host")
DFLT_FLUME_PORT = conf_parser.get("flume", "port")
LOG_LEVELS = ["DEBUG", "INFO", "WARN", "ERROR", "CRITICAL", "NONE"]
except Exception as e:
print(e)
sys.exit(-1)
arg_parser = argparse.ArgumentParser(description=DESC)
arg_parser.add_argument("--exclusions", default=DFLT_EXCLUSIONS, help="[%s]" % DFLT_EXCLUSIONS)
arg_parser.add_argument("--log-level", default="INFO", choices=LOG_LEVELS, help="[%s]" % 'INFO')
arg_parser.add_argument("--memcache-host", default=DFLT_MEMCACHE_HOST, help="[%s] if NONE, msg is dropped" % DFLT_MEMCACHE_HOST)
arg_parser.add_argument("--memcache-port", default=DFLT_MEMCACHE_PORT, help="[%s]" % DFLT_MEMCACHE_PORT)
arg_parser.add_argument("--flume-host", default=DFLT_FLUME_HOST, help="[%s] if NONE, msg is dropped" % DFLT_FLUME_HOST)
arg_parser.add_argument("--flume-port", default=DFLT_FLUME_PORT, help="[%s]" % DFLT_FLUME_PORT)
args = arg_parser.parse_args()
return {"exclusions": [] if not args.exclusions else args.exclusions.split(',')
"log_level": None if args.log_level == "NONE" else args.log_level,
"memcache_host": None if args.memcache_host == "NONE" else args.memcache_host,
"memcache_port": args.memcache_port,
"flm_host": None if args.flume_host == "NONE" else args.flume_host,
"flm_port": args.flume_port}
def main():
"""Main function."""
LOG.debug("Start : Memcached stats")
args = get_args()
set_logger(level=args["log_level"])
LOG.debug("Arguments: %s" % args)
stats = MemcachedStats(host=args["memcache_host"], port=args["memcache_port"])
send_result(stats.stats(), flume_host=args["flm_host"],flume_port=args["flm_port"], exclusions=args["exclusions"])
LOG.info("Finish: Memcached stats")
if __name__ == '__main__':
main()
#!/usr/bin/env python
from distutils.core import setup
setup(name='memcache-stats',
version='0.0',
description='Tool to publish memcache stats',
author='Cloud Infrastructure Team',
author_email='cloud-infrastructure-3rd-level@cern.ch',
url='http://www.cern.ch/openstack',
scripts=['scripts/memcache-stats'],
data_files=[("/etc/memcache-stats",["etc/memcache-stats.conf"])]
)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment