Skip to content

Commit

Permalink
Added: snmptop utility. (#142)
Browse files Browse the repository at this point in the history
* based on BaseTop interface
* `--random` support
* `--no-delta-mode` support
* added to `tests_runnable`

#143
  • Loading branch information
strizhechenko committed Jul 15, 2017
1 parent 31ff0f7 commit 960efb2
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 2 deletions.
6 changes: 5 additions & 1 deletion netutils_linux_monitoring/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ def make_table(header, align_map=None, rows=None):
""" Wrapper for pretty table """
table = PrettyTable()
table.horizontal_char = table.vertical_char = table.junction_char = ' '
table.field_names = header
try:
table.field_names = header
except Exception as err:
print_(header)
raise err
if align_map:
for field, align in zip(header, align_map):
table.align[field] = align
Expand Down
89 changes: 89 additions & 0 deletions netutils_linux_monitoring/snmptop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# coding=utf-8

from copy import deepcopy
from random import randint

from six import iteritems

from netutils_linux_monitoring.base_top import BaseTop
from netutils_linux_monitoring.layout import make_table


class SnmpTop(BaseTop):
""" Utility for monitoring IP/TCP/UDP/ICMP parts of network stack based on /proc/net/snmp values """

protos = ['IP', 'TCP', 'UDP', 'ICMP']

@staticmethod
def make_parser(parser=None):
""" :returns: parser with options for snmptop """
if not parser:
parser = BaseTop.make_parser()
parser.add_argument('--snmp-file', default='/proc/net/snmp',
help='Option for testing on MacOS purpose.')
return parser

def __int(self, line):
return [self.int(item) for item in line.strip().split()]

def eval(self):
""" Evaluates difference between snmp metrics """
self.diff = deepcopy(self.current)
for proto, data in iteritems(self.diff):
for i, metric in enumerate(data):
_, value = metric
if isinstance(value, int):
if self.options.random:
self.diff[proto][i][1] = randint(0, 1000)
else:
self.diff[proto][i][1] -= self.previous[proto][i][1]

@staticmethod
def __listify(list_of_tuples):
"""
:param list_of_tuples: list[tuple]
:return: list[list]
"""
return [list(tpl) for tpl in list_of_tuples]

def parse(self):
""" :returns: dict[proto] = list[list[str(key), int(value)]] """
with open(self.options.snmp_file) as file_fd:
lines = [self.__int(line) for line in file_fd.readlines()]
return {
'IP': self.__listify(zip(lines[0][1:], lines[1][1:])),
'ICMP': self.__listify(zip(lines[2][1:], lines[3][1:])),
'TCP': self.__listify(zip(lines[6][1:], lines[7][1:])),
'UDP': self.__listify(zip(lines[8][1:], lines[9][1:]))
}

def __repr__(self):
table = make_table(self.make_header(), self.make_align_map(), self.make_rows())
return self.__repr_table__(table)

@staticmethod
def make_header():
""" :returns: header for prettytable output (provides unique invisible whitespace-headers)
6, 5, 4 spaces are for column blinking avoidance.
"""
return ['IP', ' ' * 6, 'TCP', ' ' * 5, 'UDP', ' ' * 4, 'ICMP', '']

def make_rows(self):
""" :returns: rows for prettytable output (filled with empty values) """
rows = []
repr_source = self.repr_source()
max_len = max(len(subdict) for subdict in repr_source.values())
for index in range(max_len):
row = list()
for proto in self.protos:
if index >= len(repr_source[proto]):
row.extend(['', ''])
continue
row.extend([repr_source[proto][index][0], repr_source[proto][index][1]])
rows.append(row)
return rows

def make_align_map(self):
""" :returns: align map for prettytable output (key <-, value -> for each proto """
return ['l', 'r'] * len(self.protos)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def read(*paths):

setuptools.setup(
name='netutils-linux',
version='2.2.10',
version='2.3.0',
author='Oleg Strizhechenko',
author_email='[email protected]',
license='MIT',
Expand Down
12 changes: 12 additions & 0 deletions tests/proc_net_snmp/snmp1
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates
Ip: 1 64 22199703066 64 0 3991292426 3 0 18205118253 20899686159 1183 0 5 5 0 5 8 0 16
Icmp: InMsgs InErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps
Icmp: 17864682 762911 13469164 11533 0 53 7 4361700 21720 7 0 0 0 27650690 0 23265781 52 0 0 0 23150 4361700 0 7 0 0
IcmpMsg: InType0 InType3 InType4 InType5 InType8 InType11 InType13 OutType0 OutType3 OutType8 OutType11 OutType14
IcmpMsg: 21720 13469164 53 7 4361700 11533 7 4361700 23265781 23150 52 7
Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts
Tcp: 1 200 120000 -1 1144887168 1265503546 23608568 26172378 77 17669927663 16338441124 133674663 167169 53028318
Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors
Udp: 494467706 14809371 76 319088 0 0
UdpLite: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors
UdpLite: 0 0 0 0 0 0
12 changes: 12 additions & 0 deletions tests/proc_net_snmp/snmp2
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates
Ip: 1 64 22199717960 64 0 3991292567 3 0 18205133002 20899699894 1183 0 5 5 0 5 8 0 16
Icmp: InMsgs InErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps
Icmp: 17864706 762912 13469188 11533 0 53 7 4361700 21720 7 0 0 0 27650753 0 23265844 52 0 0 0 23150 4361700 0 7 0 0
IcmpMsg: InType0 InType3 InType4 InType5 InType8 InType11 InType13 OutType0 OutType3 OutType8 OutType11 OutType14
IcmpMsg: 21720 13469188 53 7 4361700 11533 7 4361700 23265844 23150 52 7
Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts
Tcp: 1 200 120000 -1 1144887961 1265504683 23608597 26172379 79 17669942271 16338454400 133674769 167169 53028393
Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors
Udp: 494467738 14809443 76 319088 0 0
UdpLite: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors
UdpLite: 0 0 0 0 0 0
2 changes: 2 additions & 0 deletions tests/utils_runnable
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ softirq="./tests/softirqs/i7/softirqs1"
irq="./tests/interrupts/singlequeue_8cpu/interrupts_short"
soft_net_stat="./tests/softnet_stat/softnet_stat1"
devices="eth1,eth2,eth3"
snmp="./tests/proc_net_snmp/snmp1"

network-top --no-clear -n 1 --random \
--softirqs-file="$softirq" \
Expand All @@ -16,6 +17,7 @@ link-rate --no-clear -n 1 --random --devices="$devices"
irqtop --no-clear -n 1 --random --interrupts-file="$irq"
softirq-top --no-clear -n 1 --random --softirqs-file="$softirq"
softnet-stat-top --no-clear -n 1 --random --softnet-stat-file="$soft_net_stat"
snmptop --no-clear -n 1 --random --snmp-file="$snmp"
autorps --help
autoxps --help
rss-ladder --help
10 changes: 10 additions & 0 deletions utils/snmptop
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env python

# coding: utf-8

from netutils_linux_monitoring.snmptop import SnmpTop

if __name__ == '__main__':
top = SnmpTop()
top.options = top.make_parser().parse_args()
top.run()

0 comments on commit 960efb2

Please sign in to comment.