From 4583cbafb4b43601f3039c0b8a385389a32f1887 Mon Sep 17 00:00:00 2001 From: Ben RUBSON Date: Tue, 20 Sep 2016 07:06:07 +0200 Subject: [PATCH] Network interface rate plugin for FreeBSD (#300) * Network interface rate plugin for FreeBSD * Common ifnames * typo * force flush of data to tcollector.py --- collectors/0/ifrate.py | 142 ++++++++++++++++++++++++++++++++++ collectors/etc/ifrate_conf.py | 10 +++ 2 files changed, 152 insertions(+) create mode 100755 collectors/0/ifrate.py create mode 100644 collectors/etc/ifrate_conf.py diff --git a/collectors/0/ifrate.py b/collectors/0/ifrate.py new file mode 100755 index 00000000..6c681cf6 --- /dev/null +++ b/collectors/0/ifrate.py @@ -0,0 +1,142 @@ +#!/usr/bin/env python +# This file is part of tcollector. +# Copyright (C) 2012 The tcollector Authors. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. This program is distributed in the hope that it +# will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +# General Public License for more details. You should have received a copy +# of the GNU Lesser General Public License along with this program. If not, +# see . +# + +''' +Network interfaces detailed statistics for TSDB + +This plugin tracks, for interfaces named in configuration file: + +- packets/s, input +- bytes/s, input +- errors/s, input +- drops/s, input +- packets/s, output +- bytes/s, output +- errors/s, output +- drops/s, output +- collisions/s + +Requirements : +- FreeBSD : netstat +''' + +import errno +import sys +import time +import subprocess +import re +import signal +import os +import platform + +from collectors.lib import utils + +try: + from collectors.etc import ifrate_conf +except ImportError: + ifrate_conf = None + +DEFAULT_COLLECTION_INTERVAL=15 + +signal_received = None +def handlesignal(signum, stack): + global signal_received + signal_received = signum + +def main(): + """top main loop""" + + collection_interval=DEFAULT_COLLECTION_INTERVAL + if(ifrate_conf): + config = ifrate_conf.get_config() + collection_interval=config['collection_interval'] + interfaces=config['interfaces'] + + global signal_received + + signal.signal(signal.SIGTERM, handlesignal) + signal.signal(signal.SIGINT, handlesignal) + + p_net = [] + intnum = 0 + try: + if platform.system() == "FreeBSD": + for intname in interfaces: + p_net.append(subprocess.Popen( + ["netstat", "-I", intname, "-d", "-w", str(collection_interval)], + stdout=subprocess.PIPE, + )) + intnum+=1 + else: + sys.exit(13) # we signal tcollector to not run us + except OSError, e: + if e.errno == errno.ENOENT: + # it makes no sense to run this collector here + sys.exit(13) # we signal tcollector to not run us + raise + + timestamp = 0 + procnum = 0 + + while signal_received is None: + if (procnum >= intnum): + procnum=0 + try: + line = p_net[procnum].stdout.readline() + except (IOError, OSError), e: + if e.errno in (errno.EINTR, errno.EAGAIN): + break + raise + + if not line: + # end of the program, die + break + + if (re.match("^[0-9 ]+$",line)): + fields = line.split() + if len(fields) == 9: + if(procnum == 0): + timestamp = int(time.time()) + print ("ifrate.pkt.in %s %s int=%s" % (timestamp, int(fields[0])/collection_interval, interfaces[procnum])) + print ("ifrate.err.in %s %s int=%s" % (timestamp, int(fields[1])/collection_interval, interfaces[procnum])) + print ("ifrate.drp.in %s %s int=%s" % (timestamp, int(fields[2])/collection_interval, interfaces[procnum])) + print ("ifrate.byt.in %s %s int=%s" % (timestamp, int(fields[3])/collection_interval, interfaces[procnum])) + print ("ifrate.pkt.out %s %s int=%s" % (timestamp, int(fields[4])/collection_interval, interfaces[procnum])) + print ("ifrate.err.out %s %s int=%s" % (timestamp, int(fields[5])/collection_interval, interfaces[procnum])) + print ("ifrate.byt.out %s %s int=%s" % (timestamp, int(fields[6])/collection_interval, interfaces[procnum])) + print ("ifrate.col %s %s int=%s" % (timestamp, int(fields[7])/collection_interval, interfaces[procnum])) + print ("ifrate.drp.out %s %s int=%s" % (timestamp, int(fields[8])/collection_interval, interfaces[procnum])) + + # analyze next process + procnum+=1 + + sys.stdout.flush() + + if signal_received is None: + signal_received = signal.SIGTERM + try: + for procnum in range(0, intnum): + os.kill(p_net[procnum].pid, signal_received) + except Exception: + pass + for procnum in range(0, intnum): + p_net[procnum].wait() + + # If no line at all has been proceeded (wrong interface name ?), we signal tcollector to not run us + if(timestamp == 0): + exit(13) + +if __name__ == "__main__": + main() diff --git a/collectors/etc/ifrate_conf.py b/collectors/etc/ifrate_conf.py new file mode 100644 index 00000000..ee2dabe8 --- /dev/null +++ b/collectors/etc/ifrate_conf.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +def get_config(): + + config = { + 'collection_interval': 15, # Seconds, how often to collect metric data + 'interfaces': ['ix0','ix1'] # Interfaces to monitor + } + + return config