Commit 606df697 by Bach Dániel

add disk io metric

parent 5a251e2c
*.pyc
*.swp
[Client]
Debug = False
[Metrics]
cpuUsage = 5
cpuTimes = 5
memoryUsage = 5
userCount = 60
swapUsage = 30
systemBootTime = 120
packageTraffic = 10
dataTraffic = 10
[KVM]
cpuUsage = 5
memoryUsage = 5
networkUsage = 5
import logging import logging
import sys import sys
from src import cnfparse from src.client import Client
from src import client
from src.collectables import collectables
def main(): def main():
...@@ -16,10 +14,8 @@ def main(): ...@@ -16,10 +14,8 @@ def main():
if len(sys.argv) is not 2 and sys.argv[1] is not "run": if len(sys.argv) is not 2 and sys.argv[1] is not "run":
print("[ERROR] Command cannot be parsed. Exiting...") print("[ERROR] Command cannot be parsed. Exiting...")
return return
configuration, metrics = cnfparse.import_conf("config/client.conf")
cli = client.Client(configuration) Client().run()
metricCollectors = collectables.provide(metrics)
cli.run(metricCollectors)
if __name__ == "__main__": if __name__ == "__main__":
......
#!/usr/bin/python #!/usr/bin/python
from datetime import datetime
from itertools import islice from itertools import islice
from socket import gethostname from socket import gethostname
import argparse import argparse
import logging import logging
import operator
import os import os
import pika import pika
import psutil import psutil
...@@ -25,7 +23,7 @@ class Client: ...@@ -25,7 +23,7 @@ class Client:
"amqp_vhost": "GRAPHITE_AMQP_VHOST", "amqp_vhost": "GRAPHITE_AMQP_VHOST",
} }
def __init__(self, config): def __init__(self):
""" """
Constructor of the client class that is responsible for handling the Constructor of the client class that is responsible for handling the
communication between the graphite server and the data source. In communication between the graphite server and the data source. In
...@@ -46,11 +44,6 @@ class Client: ...@@ -46,11 +44,6 @@ class Client:
setattr(self, var, value) setattr(self, var, value)
else: else:
raise RuntimeError('%s environment variable missing' % env_var) raise RuntimeError('%s environment variable missing' % env_var)
self.debugMode = config["debugMode"]
self.kvmCPU = int(config["kvmCpuUsage"])
self.kvmMem = int(config["kvmMemoryUsage"])
self.kvmNet = int(config["kvmNetworkUsage"])
self.beat = 0
def connect(self): def connect(self):
""" """
...@@ -86,7 +79,8 @@ class Client: ...@@ -86,7 +79,8 @@ class Client:
self.channel.close() self.channel.close()
self.connection.close() self.connection.close()
except RuntimeError as e: except RuntimeError as e:
logger.error('An error has occured while disconnecting. %s', unicode(e)) logger.error('An error has occured while disconnecting. %s',
unicode(e))
raise raise
def send(self, message): def send(self, message):
...@@ -105,24 +99,39 @@ class Client: ...@@ -105,24 +99,39 @@ class Client:
len(body)) len(body))
raise raise
def collect_node(self, metricCollectors): def collect_node(self):
""" """
It harvests the given metrics in the metricCollectors list. This list It harvests the given metrics in the metricCollectors list. This list
should be provided by the collectables modul. It is important that should be provided by the collectables modul. It is important that
only the information collected from the node is provided here. only the information collected from the node is provided here.
""" """
metrics = []
for collector in metricCollectors: now = time.time()
collector_function = collector[0] metrics = {
phase = collector[1] 'cpu.usage': psutil.cpu_percent(interval=0.0),
if self.beat % phase == 0: 'cpu.times': psutil.cpu_times().user + psutil.cpu_times().system,
stat = collector_function() 'memory.usage': psutil.virtual_memory().percent,
metrics.append(('%(hostname)s.%(name)s %(value)f %(time)d') % 'swap.usage': psutil.swap_memory().percent,
{'hostname': self.name, 'user.count': len(psutil.get_users()),
'name': stat.name, 'system.boot_time': psutil.get_boot_time()
'value': stat.value, }
'time': time.time()})
return metrics for k, v in psutil.disk_io_counters().__dict__.items():
metrics['disk.%s' % k] = v
interfaces = psutil.network_io_counters(pernic=True)
for interface, data in interfaces.iteritems():
if not interface.startswith('cloud-'):
for metric in ('packets_sent', 'packets_recv',
'bytes_sent', 'bytes_recv'):
metrics['network.%s-%s' %
(metric, interface)] = getattr(data, metric)
return ['%(host)s.%(name)s %(val)f %(time)d' % {'host': self.name,
'name': name,
'val': value,
'time': now}
for name, value in metrics.iteritems()]
def collect_vms(self): def collect_vms(self):
""" """
...@@ -133,24 +142,20 @@ class Client: ...@@ -133,24 +142,20 @@ class Client:
metrics = [] metrics = []
now = time.time() now = time.time()
running_vms = [] running_vms = []
beats = {
'mem': self.beat % self.kvmMem == 0,
'cpu': self.beat % self.kvmCPU == 0,
'net': self.beat % self.kvmNet == 0
}
if beats['cpu'] or beats['mem']:
for entry in psutil.get_process_list(): for entry in psutil.get_process_list():
try: try:
if entry.name == 'kvm': if entry.name == 'kvm':
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('-name') parser.add_argument('-name')
parser.add_argument('--memory-size', '-m ', type=int) parser.add_argument('--memory-size', '-m ', type=int)
args, unknown = parser.parse_known_args(entry.cmdline[1:]) args, unknown = parser.parse_known_args(
entry.cmdline[1:])
process = psutil.Process(entry.pid) process = psutil.Process(entry.pid)
mem_perc = process.get_memory_percent() / 100 * args.memory_size mem_perc = (process.get_memory_percent()
/ 100 * args.memory_size)
metrics.append('vm.%(name)s.memory.usage %(value)f ' metrics.append('vm.%(name)s.memory.usage %(value)f '
'%(time)d' % {'name': args.name, '%(time)d' % {'name': args.name,
'value': mem_perc, 'value': mem_perc,
...@@ -165,9 +170,8 @@ class Client: ...@@ -165,9 +170,8 @@ class Client:
except psutil.NoSuchProcess: except psutil.NoSuchProcess:
logger.warning('Process %d lost.', entry.pid) logger.warning('Process %d lost.', entry.pid)
interfaces_list = psutil.network_io_counters(pernic=True) interfaces = psutil.network_io_counters(pernic=True)
if beats['net']: for interface, data in interfaces.iteritems():
for interface, data in interfaces_list.iteritems():
try: try:
vm, vlan = interface.rsplit('-', 1) vm, vlan = interface.rsplit('-', 1)
except ValueError: except ValueError:
...@@ -184,21 +188,13 @@ class Client: ...@@ -184,21 +188,13 @@ class Client:
'time': now, 'time': now,
'data': getattr(data, metric)}) 'data': getattr(data, metric)})
if (self.beat % 30) == 0:
metrics.append( metrics.append(
('%(host)s.vmcount %(data)d %(time)d') % '%(host)s.vmcount %(data)d %(time)d' % {
{'host': self.name, 'host': self.name,
'data': len(running_vms), 'data': len(running_vms),
'time': time.time()}) 'time': time.time()})
return metrics
def get_frequency(self, metricCollectors=[]): return metrics
"""
"""
items = metricCollectors + [["kvmCpuUsage", self.kvmMem], [
"kvmMemoryUsage", self.kvmCPU], ["kvmNetworkUsage", self.kvmNet]]
freqs = set([i[1] for i in items if i[1]>0])
return reduce(operator.mul, freqs, 1)
@staticmethod @staticmethod
def _chunker(seq, size): def _chunker(seq, size):
...@@ -207,7 +203,7 @@ class Client: ...@@ -207,7 +203,7 @@ class Client:
for pos in xrange(0, len(seq), size): for pos in xrange(0, len(seq), size):
yield islice(seq, pos, pos + size) yield islice(seq, pos, pos + size)
def run(self, metricCollectors=[]): def run(self):
""" """
Call this method to start reporting to the server, it needs the Call this method to start reporting to the server, it needs the
metricCollectors parameter that should be provided by the collectables metricCollectors parameter that should be provided by the collectables
...@@ -215,22 +211,13 @@ class Client: ...@@ -215,22 +211,13 @@ class Client:
""" """
self.connect() self.connect()
try: try:
maxFrequency = self.get_frequency(metricCollectors)
while True: while True:
nodeMetrics = self.collect_node(metricCollectors) metrics = self.collect_node() + self.collect_vms()
vmMetrics = self.collect_vms()
metrics = nodeMetrics + vmMetrics
if metrics: if metrics:
if self.debugMode == "True":
for i in metrics:
logger.debug('Metric to send: %s', i)
for chunk in self._chunker(metrics, 100): for chunk in self._chunker(metrics, 100):
self.send(chunk) self.send(chunk)
logger.info("%d metrics sent", len(metrics)) logger.info("%d metrics sent", len(metrics))
time.sleep(1) time.sleep(10)
self.beat += 1
if self.beat % maxFrequency == 0:
self.beat = 0
except KeyboardInterrupt: except KeyboardInterrupt:
logger.info("Reporting has stopped by the user. Exiting...") logger.info("Reporting has stopped by the user. Exiting...")
finally: finally:
......
import sys
if sys.version_info < (3, 0):
import ConfigParser as configparser
else:
import configparser
def import_conf(path_to_file):
config = configparser.RawConfigParser(allow_no_value=False)
try:
config.read(path_to_file)
params = {}
metrics = {}
params["debugMode"] = config.get("Client", "Debug")
##
## Metrics
##
metrics["cpu.usage"] = int(config.get("Metrics", "cpuUsage"))
metrics["cpu.times"] = int(config.get("Metrics", "cpuTimes"))
metrics["memory.usage"] = int(config.get("Metrics", "memoryUsage"))
metrics["user.count"] = int(config.get("Metrics", "userCount"))
metrics["swap.usage"] = int(config.get("Metrics", "swapUsage"))
metrics["system.boot_time"] = int(config.get("Metrics",
"systemBootTime"))
metrics["network"] = int(config.get("Metrics", "dataTraffic"))
##
## Params
##
params["kvmCpuUsage"] = int(config.get("KVM", "cpuUsage"))
params["kvmMemoryUsage"] = int(config.get("KVM", "memoryUsage"))
params["kvmNetworkUsage"] = int(config.get("KVM", "networkUsage"))
except configparser.NoSectionError:
print("[ERROR] Config file contains error! "
"Reason: Missing section.")
raise
except configparser.ParsingError:
print("[ERROR] Config file contains error! "
"Reason: Cannot parse.")
raise
except configparser.MissingSectionHeaderError:
print("[ERROR] Config file contains error! "
"Reason: Missing section-header.")
raise
return params, metrics
from metrics import std
class collectables:
__collectables = {
std.cpu.usage.name: [std.cpu.usage],
std.cpu.times.name: [std.cpu.times],
std.memory.usage.name: [std.memory.usage],
std.swap.usage.name: [std.swap.usage],
std.user.count.name: [std.user.count],
std.network.packages_sent.name: [std.network.packages_sent],
std.network.packages_received.name: [std.network.packages_received],
std.network.bytes_sent.name: [std.network.bytes_sent],
std.network.bytes_received.name: [std.network.bytes_received],
std.system.boot_time.name: [std.system.boot_time],
"network": [std.network.bytes_sent, std.network.bytes_received,
std.network.packages_sent, std.network.packages_received],
}
@staticmethod
def list_keys():
return list(collectables.__collectables.keys())
@staticmethod
def list_metrics_to_key(key):
return collectables.__collectables[key]
@staticmethod
def list_metrics_name_to_key(key):
return [x.name for x in collectables.__collectables[key]]
@staticmethod
def provide(requests=[]):
reqs = []
for requests, value in requests.items():
if value > 0:
reqs.append([requests, value])
collectors = []
for request in reqs:
for item in collectables.__collectables[request[0]]:
collectors.append([item.harvest, request[1]])
return collectors
@staticmethod
def provideAll():
return collectables.provide(collectables.list_keys())
#!/usr/bin/python
import psutil as ps
import collections
#############################################################################
Metrics = collections.namedtuple("Metrics", ["name", "value"])
class Collection(object):
class Group(object):
class Metric(object):
name = "unknown"
collector_function = 0
collector_function_arguments = {}
collector_function_result_attr = ""
@classmethod
def harvest(cls):
query = cls.collector_function.im_func(
**cls.collector_function_arguments)
if ((isinstance(query, list)) or (isinstance(query, dict))):
return Metrics(cls.name,
query[cls.collector_function_result_attr])
elif (isinstance(query, tuple)):
return Metrics(cls.name, query.__getattribute__(
cls.collector_function_result_attr))
else:
return Metrics(cls.name, query)
##############################################################################
class std(Collection):
class cpu(Collection.Group):
class usage(Collection.Group.Metric):
name = "cpu.usage"
collector_function = ps.cpu_percent
collector_function_arguments = {'interval': 0.0}
class times(Collection.Group.Metric):
name = "cpu.times"
@classmethod
def harvest(cls):
return Metrics(cls.name,
ps.cpu_times().user + ps.cpu_times().system)
class memory(Collection.Group):
class usage(Collection.Group.Metric):
name = "memory.usage"
collector_function = ps.virtual_memory
collector_function_result_attr = "percent"
class swap(Collection.Group):
class usage(Collection.Group.Metric):
name = "swap.usage"
collector_function = ps.swap_memory
collector_function_result_attr = "percent"
class user(Collection.Group):
class count(Collection.Group.Metric):
name = "user.count"
@classmethod
def harvest(cls):
return Metrics(cls.name, len(ps.get_users()))
class network(Collection.Group):
class packages_sent(Collection.Group.Metric):
name = "network.packets_sent"
collector_function = ps.network_io_counters
collector_function_result_attr = "packets_sent"
class packages_received(Collection.Group.Metric):
name = "network.packets_recv"
collector_function = ps.network_io_counters
collector_function_result_attr = "packets_recv"
class bytes_sent(Collection.Group.Metric):
name = "network.bytes_sent"
collector_function = ps.network_io_counters
collector_function_result_attr = "bytes_sent"
class bytes_received(Collection.Group.Metric):
name = "network.bytes_received"
collector_function = ps.network_io_counters
collector_function_result_attr = "bytes_recv"
class system(Collection.Group):
class boot_time(Collection.Group.Metric):
name = "system.boot_time"
collector_function = ps.get_boot_time
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 sign in to comment