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/env python | |
from commands import getstatusoutput | |
from platform import node | |
from socket import socket, AF_INET, SOCK_STREAM | |
from sys import argv, exit | |
from time import sleep, time | |
from daemon import runner | |
import re | |
DELAY = 60 | |
CARBON_SERVER = '192.168.1.250' | |
CARBON_PORT = 2003 | |
class Carbon: | |
def __init__(self, hostname, port): | |
self.s = socket(AF_INET, SOCK_STREAM) | |
self.hostname = hostname | |
self.port = int(port) | |
self.connect() | |
def connect(self): | |
try: | |
self.s.connect((self.hostname, self.port)) | |
except IOError, e: | |
print "connect: ", e | |
return | |
def disconnect(self): self.s.close() | |
def send(self, data): | |
try: | |
self.s.sendall(data + "\n") | |
except: | |
self.connect() | |
self.s.sendall(data + "\n") | |
class Host: | |
def __init__(self): | |
self.historical = {} | |
def get_all(self): | |
data = [] | |
functions = dir(self) | |
for function in functions: | |
if not function.startswith("fetch_"): continue | |
for metric in eval("self.%s()" % (function)): | |
data.append(metric) | |
return data | |
def read_file(self, filename): | |
file_handle = open(filename) | |
contents = file_handle.readlines() | |
file_handle.close() | |
return contents | |
def delta_analyzer(self, measurements, data, now): | |
result = [] | |
for line in data: | |
for measurement, loc in measurements.iteritems(): | |
metric_name = "%s.%s" % (line[0], measurement) | |
try: value = line[loc] | |
except: continue | |
if self.historical.has_key(metric_name): | |
current = value | |
delta = int(value) - int(self.historical[metric_name][1]) | |
timedelta = time() - self.historical[metric_name][0] | |
self.historical[metric_name] = (time(), current) | |
if timedelta < 1: | |
continue | |
value = int( delta / timedelta ) | |
if value > 0: | |
result.append("%s %d %d" % (metric_name, value, now)) | |
else: | |
self.historical[metric_name] = (time(), value) | |
return result | |
def fetch_loadavg(self): | |
data = [] | |
now = int(time()) | |
(loadavg_1, loadavg_5, loadavg_15) = self.read_file("/proc/loadavg")[0].strip().split()[:3] | |
data.append("load.1min %s %d" % (loadavg_1,now)) | |
data.append("load.5min %s %d" % (loadavg_5,now)) | |
data.append("load.15min %s %d" % (loadavg_15,now)) | |
return data | |
def fetch_network_io(self): | |
measurements = {"rx_bytes": 1, "rx_packets": 2, "rx_errors": 3, "rx_dropped": 4, "tx_bytes": 9, "tx_packets": 10, "tx_errors": 11, "tx_dropped": 12} | |
now = int(time()) | |
raw_data = self.read_file("/proc/net/dev") | |
prepared_data = [] | |
for line in raw_data[2:]: | |
(interface, values) = line.strip().split(":") | |
values = values.split() | |
if interface == "lo": continue | |
values.insert(0, "network." + interface) | |
prepared_data.append(values) | |
return self.delta_analyzer(measurements, prepared_data, now) | |
def fetch_disk_usage(self): | |
data = [] | |
now = int(time()) | |
(status, raw_data) = getstatusoutput("mount") | |
if status != 0: return data | |
for line in raw_data.split("\n"): | |
if not (line.startswith("/") or line.find("@o2ib") >= 0): continue | |
device = line.split()[2] | |
device_name = line.split()[0].split('/')[-1] | |
(status, device_data) = getstatusoutput("stat -c '%s %a %b %c %d %f' -f " + device) | |
if status != 0: continue | |
block_size, free_blocks_nonsu, total_blocks, total_file_nodes, free_file_nodes, free_blocks = [a.isdigit() and int(a) or 0 for a in device_data.split()] | |
data.append("disk.%s.available %d %d" % (device_name, free_blocks*block_size, now)) | |
data.append("disk.%s.free_inodes %d %d" % (device_name, free_file_nodes, now)) | |
data.append("disk.%s.available_percent %f %d" % (device_name, float(free_blocks)/total_blocks*100, now)) | |
return data | |
def fetch_disk_io(self): | |
measurements = {"reads_issued": 3, "ms_spent_reading": 6, "writes_completed": 7, "ms_spent_writing": 10, "ios_in_progress": 11, "ms_spent_doing_io": 12, "weighted_ms_spent_doing_io": 13} | |
now = int(time()) | |
raw_data = self.read_file("/proc/diskstats") | |
prepared_data = [] | |
for line in raw_data: | |
values = line.split() | |
values[0] = "disk." + values[2] | |
prepared_data.append(values) | |
return self.delta_analyzer(measurements, prepared_data, now) | |
def fetch_memory_usage(self): | |
metrics = {"MemFree": "memory_free", "Buffers": "buffers", "Cached": "cached", "SwapFree": "swap_free", "Slab": "slab"} | |
data = [] | |
now = int(time()) | |
raw_data = self.read_file("/proc/meminfo") | |
for line in raw_data: | |
metric, i = line.split(":") | |
value = int(i.strip().strip(" kB")) * 1024 | |
if metric in metrics.keys(): | |
data.append("memory.%s %d %d" % (metrics[metric], value, now)) | |
return data | |
def fetch_smb_statistics(self): | |
measurements = {0: "clients", 2: "file_locks"} | |
data = [] | |
now = int(time()) | |
this_node = None | |
(status, raw_data) = getstatusoutput("/usr/bin/ctdb status") | |
if status == 0: | |
for line in raw_data.split("\n"): | |
if line.find("THIS NODE") > 0: | |
this_node = line.split()[0].split(":")[1] | |
if this_node is None: return | |
(status, raw_data) = getstatusoutput("/usr/bin/smbstatus") | |
if status != 0: return data | |
for i, block in enumerate(raw_data.split("\n\n")): | |
if i not in measurements.keys(): continue | |
raw_data = block.split("\n") | |
if this_node is not None: | |
this_node_count = [line.startswith(this_node + ":") for line in raw_data].count(True) | |
else: | |
this_node_count = len(raw_data) - 4 | |
if this_node_count < 0: this_node_count = 0 | |
data.append("smb.%s %d %d" % (measurements[i], this_node_count, now)) | |
return data | |
def fetch_cpu_temperature(self): | |
data = [] | |
now = int(time()) | |
raw_data = self.read_file("/sys/class/thermal/thermal_zone0/temp") | |
value = int(raw_data[0]) * 0.001 | |
data.append("cpu.temp %d %d" % (value, now) ) | |
return data | |
def fetch_gpu_temperature(self): | |
data = [] | |
now = int(time()) | |
(status, raw_data) = getstatusoutput('/opt/vc/bin/vcgencmd measure_temp') | |
if status == 0: | |
value = float(raw_data.replace('temp=','').replace('\'C','')) | |
else: | |
value = float(0.0) | |
data.append("gpu.temp %d %d" % (value, now) ) | |
return data | |
def fetch_logged_in_users(self): | |
data = [] | |
now = int(time()) | |
(status, raw_data) = getstatusoutput("/usr/bin/users") | |
value = len(raw_data.split(" ")) | |
data.append("users.count %d %d" % (value, now) ) | |
return data | |
def fetch_wireless_stats(self): | |
data = [] | |
measurements = [] | |
now = int(time()) | |
(stats, raw_data) = getstatusoutput('/sbin/iwconfig wlan0 | grep -e "Bit\ Rate" -e "Link\ Quality"') | |
for line in raw_data.split("\n"): | |
for item in line.lstrip().rstrip().split(" "): | |
measurements.append(item.strip()) | |
for item in measurements: | |
if item.find(":") > 0: | |
(key, value) = item.split(":") | |
elif item.find("=") > 0: | |
(key, value) = item.split("=") | |
value = re.search('^([0-9]+)', value).group(0) | |
key = re.sub('\s+', '_', key).lower() | |
data.append('wireless.%s %d %d' % (key, int(value), now)) | |
return data | |
class App(): | |
def __init__(self): | |
self.stdin_path = '/dev/null' | |
self.stdout_path = '/dev/stdout' | |
self.stderr_path = '/dev/stderr' | |
self.pidfile_path = '/var/run/collectord.py.pid' | |
self.pidfile_timeout = 5 | |
def run(self): | |
host = Host() | |
hostname = node().split('.')[0] | |
graphite = Carbon(CARBON_SERVER, CARBON_PORT); | |
while True: | |
data = host.get_all() | |
for datum in data: | |
metric = "system.%s.%s" % (hostname, datum) | |
if "-debug" in argv: | |
print metric | |
graphite.send(metric) | |
sleep(DELAY) | |
if __name__ == '__main__': | |
app = App() | |
daemon_runner = runner.DaemonRunner(app) | |
daemon_runner.do_action() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment