python工具—snmp流量监控,自定义粒度,业务突发可视化

现在主流监控软件和云平台提供的流量监控,监控粒度最小只能设置为1分钟,无法准确定位故障,特别是瞬时突发较大的业务

对比python的snmp库还是更喜欢用subprocess调用snmpwalk命令,脚本如下,前端可以使用脚本采集到的数据进行绘图

snmpwalk版本,系统需要安装 snmp snmp-mibs-downloader

#! /usr/bin/env python
#-*-coding:utf-8-*-
# yum -y install net-snmp-libs net-snmp net-snmp-utils
# apt install snmp snmp-mibs-downloader
# vi /etc/snmp/snmp.conf
import time,subprocess,re,signal,os,sys
class traffic:  
    def __init__(self,ip,port,community,interval):
        try:
            cmd_index = 'snmpwalk -v 2c -c %s %s  IF-MIB::ifDescr | grep -w %s'%(community,ip,port) 
            portindex = subprocess.Popen(cmd_index,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()[0]
            ret = re.findall('ifDescr.\d+',portindex.decode('utf8'))[0]
            portMIB = int(re.findall('\d+',ret)[0])
            self.cmd_in='snmpwalk -v 2c -c %s %s ifHCInOctets.%s'%(community,ip,portMIB) 
            self.cmd_out='snmpwalk -v 2c -c %s %s ifHCOutOctets.%s'%(community,ip,portMIB) 
            self.interval = interval
        except:
            print('please check snmp and snmp-mibs-downloader')
            print('-----------------examples-----------------------')
            print('dpkg -l | grep snmp')
            print('sudo > /etc/snmp/snmp.conf')
            sys.exit(0)
    def form(self,data):
        ret = re.findall('Counter64:.*',data.decode('utf8'))[0]
        ret = ret.split(':')[1].strip()
        ret = round(int(ret)*8/1024/1024,2)
        return ret
    def snmp(self):
        traffic_in =  subprocess.Popen(self.cmd_in,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()[0]
        traffic_out = subprocess.Popen(self.cmd_out,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()[0]
        traffic_in = self.form(traffic_in)
        traffic_out = self.form(traffic_out)
        return(traffic_in,traffic_out)
    def gettraffic(self):
        befo_in,befo_out = self.snmp() 
        time.sleep(self.interval)
        after_in,after_out = self.snmp()
        return ({'in':round((after_in-befo_in)/self.interval,2),'out':round((after_out-befo_out)/self.interval,2)})
def signal_handler(*args, **kwargs):
    try:
        if count!=0:
            print('----------------------------end-----------------------------')
            print('               min          max          avg')
            print('incoming    %sM        %sM        %sM'%(traffic_in_min,traffic_in_max,round(traffic_in_sum/count,2)))
            print('outgoing    %sM        %sM        %sM'%(traffic_out_min,traffic_out_max,round(traffic_out_sum/count,2)))
    except:
        os._exit(0)
    os._exit(0)
if __name__  == "__main__":
    write, flush = sys.stdout.write, sys.stdout.flush 
    signal.signal(signal.SIGINT, signal_handler)
    traffic_in_max = 0
    traffic_out_max = 0
    traffic_in_min = 999999999999
    traffic_out_min = 999999999999
    traffic_in_sum = 0
    traffic_out_sum = 0
    count = 0
    try:
        host = sys.argv[1]
        port = sys.argv[2]
        community = sys.argv[3]
        interval = int(sys.argv[4])
        mx =traffic(host,port,community,interval)
        print('-------------%s %s秒粒度流量监控------------------'%(host,interval))
        while True:
            ret = mx.gettraffic()
            traffic_in = ret['in']
            traffic_out = ret['out']
            traffic_in_max = max(traffic_in,traffic_in_max)
            traffic_out_max = max(traffic_out,traffic_out_max)
            traffic_in_min = min(traffic_in,traffic_in_min)
            traffic_out_min = min(traffic_out,traffic_out_min)
            traffic_in_sum += traffic_in
            traffic_out_sum += traffic_out
            count+=1
            ret = 'traffic_in: %s Mbps'%traffic_in+' '+'traffic_out: %s Mbps'%traffic_out
            write(ret)
            flush()
            write('\x08'*len(ret))
        # print('traffic_in: %s Mbps'%traffic_in,'traffic_out: %s Mbps'%traffic_out)
    except:
        print('usage:')
        print('    <host> <portMIB> <community> <interval>')
        print('options:')
        print('    host: <dest_ip>')
        print('    portMIB <dest port>')
        print('    community: <community>')
        print('    interval: <get data interval>')
        print('examples:')
        print('    ./traffic 10.0.0.1 ge-0/0/46 public 5')

pysnmp版本 pip install pysnmp

#! /usr/bin/env python
#-*-coding:utf-8-*-
from pysnmp.hlapi import *
import time,os,signal,sys
class port_traffic_index:
    def __init__(self,community,host,port):
        self.community = community
        self.host = (host,161)
        self.port=port
    #获取接口数量
    @property
    def index_count(self):
        iterator = getCmd(SnmpEngine(),
                        CommunityData(self.community),
                        UdpTransportTarget(self.host),
                        ContextData(),
                        ObjectType(ObjectIdentity('IF-MIB', 'ifNumber', 0)))
        errorIndication, errorStatus, errorIndex, varBinds = next(iterator)
        for varBind in varBinds:
            mib,count=[x.prettyPrint() for x in varBind]
        return int(count)
    #获取接口对应的mib index值
    def port_index(self):
            port_count = self.index_count
            N,R=0,1000
            iterator = bulkCmd(SnmpEngine(),
                            CommunityData(self.community),
                            UdpTransportTarget(self.host),
                            ContextData(),
                            N,R,
                            ObjectType(ObjectIdentity('IF-MIB','ifDescr')))
            for x in range(port_count):
                errorIndication, errorStatus, errorIndex, varBinds = next(iterator)
                if errorIndication:  # SNMP engine errors
                    print(errorIndication)
                else:
                    if errorStatus:  # SNMP agent errors
                        print('%s at %s' % (errorStatus.prettyPrint(), varBinds[int(errorIndex)-1] if errorIndex else '?'))
                    else:
                        for varBind in varBinds:  # SNMP response contents
                            #接口mib与接口名称做为一个列表,分别赋值给mib,port
                            mib,port=[x.prettyPrint() for x in varBind]
                            if port == self.port:
                                mib1,mib_index=mib.split('.')
                                return int(mib_index)
    #获取接口流量
    def port_traffic(self,index):
        iterator = getCmd(SnmpEngine(),
                  CommunityData(self.community),
                  UdpTransportTarget(self.host),
                  ContextData(),
                  ObjectType(ObjectIdentity('IF-MIB', 'ifHCInOctets', index)),
                  ObjectType(ObjectIdentity('IF-MIB', 'ifHCOutOctets', index)))
        errorIndication, errorStatus, errorIndex, varBinds = next(iterator)
        t_in,t_out =  varBinds  # SNMP response contents,有两个对象分别对应请求的mib
        key_in,traffic_in=[x.prettyPrint() for x in t_in]
        key_out,traffic_out=[x.prettyPrint() for x in t_out]
        return int(traffic_in),int(traffic_out)

    def get_traffic(self,port_index,interval):
        inittraffic_in,inittraffic_out = self.port_traffic(port_index)
        time.sleep(interval)
        aftraffic_in,aftraffic_out = self.port_traffic(port_index)
        traffic_in = round((aftraffic_in-inittraffic_in)*8/1024/1024/interval,2)
        traffic_out = round((aftraffic_out-inittraffic_out)*8/1024/1024/interval,2)
        return traffic_in,traffic_out

def signal_handler(*args, **kwargs):
    try:
        if count!=0:
            print('----------------------------end-----------------------------')
            print('               min          max          avg')
            print('incoming    %sM        %sM        %sM'%(traffic_in_min,traffic_in_max,round(traffic_in_sum/count,2)))
            print('outgoing    %sM        %sM        %sM'%(traffic_out_min,traffic_out_max,round(traffic_out_sum/count,2)))
    except:
        os._exit(0)
    os._exit(0)

if __name__ == '__main__': 
    write, flush = sys.stdout.write, sys.stdout.flush 
    signal.signal(signal.SIGINT, signal_handler)                                        
    traffic_in_max = 0
    traffic_out_max = 0
    traffic_in_min = 999999999999
    traffic_out_min = 999999999999
    traffic_in_sum = 0
    traffic_out_sum = 0
    count = 0
    try:
        host = sys.argv[1]
        port = sys.argv[2]
        community = sys.argv[3]
        interval = int(sys.argv[4])
        traffic = port_traffic_index(community, host, port)
        port_index = traffic.port_index()
        print('-------------%s %s秒粒度流量监控------------------'%(host,interval))
        while True:
            traffic_in,traffic_out = traffic.get_traffic(port_index, interval)
            traffic_in_max = max(traffic_in,traffic_in_max)
            traffic_out_max = max(traffic_out,traffic_out_max)
            traffic_in_min = min(traffic_in,traffic_in_min)
            traffic_out_min = min(traffic_out,traffic_out_min)
            traffic_in_sum += traffic_in
            traffic_out_sum += traffic_out
            count+=1
            ret = 'traffic_in: %s Mbps'%traffic_in+' '+'traffic_out: %s Mbps'%traffic_out
            write(ret)
            flush()
            write('\x08'*len(ret))
            # print('traffic_in: %s Mbps'%traffic_in,'traffic_out: %s Mbps'%traffic_out)
    except:
        print('usage:')
        print('    <host> <portMIB> <community> <interval>')
        print('options:')
        print('    host: <dest_ip>')
        print('    portMIB <dest port>')
        print('    community: <community>')
        print('    interval: <get data interval>')
        print('examples:')
        print('    ./pytraffic 10.0.0.1 ge-0/0/46 public 5')

Leave a Reply

Your email address will not be published. Required fields are marked *

X