Skip to content

Assert mode #135

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion netutils_linux_monitoring/base_top.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from colorama import Fore
from six import print_

from netutils_linux_monitoring.colors import wrap
from netutils_linux_monitoring.colors import wrap, Metric


class BaseTop(object):
Expand All @@ -16,6 +16,7 @@ class BaseTop(object):
diff = None
header = wrap("Press CTRL-C to exit...\n", Fore.LIGHTBLACK_EX)
options = None
state = Metric()

def __init__(self):
"""
Expand Down
61 changes: 60 additions & 1 deletion netutils_linux_monitoring/colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,64 @@
}


class State(object):
""" I'd like to use enum from py34+, but I need support for py26 and afraid to use enum34 from PYPI """
OK = 0
WARNING = 1
ERROR = 2

@staticmethod
def fsm(value, warning, error):
""" Nice place to apply FSM later """
return State.ERROR if value >= error else State.WARNING if value >= warning else State.OK


class Metric(State):
"""
In these utils exist a lot of metrics.
Many of them have warning/error threshold and need to be highlighted
"""

value = None
warning = None
error = None

state = State.OK
colors = {
State.OK: Fore.RESET,
State.ERROR: Fore.RED,
State.WARNING: YELLOW
}

def __init__(self):
self.text = self.colorize()

def init(self, value):
""" :returns: initialized object (assuming you inherited Metric) """
assert self.warning is not None and self.error is not None
self.__set_value(value)
self.state = State.fsm(value, self.warning, self.error)
return self

def init_raw(self, value, warning, error):
""" :returns: initialized object with ready-to-use thresholds """
self.__set_warning(warning)
self.__set_error(error)
return self.init(value)

def __set_value(self, value):
self.value = value

def __set_warning(self, warning):
self.warning = warning

def __set_error(self, error):
self.error = error

def colorize(self):
return wrap(self.value, Metric.colors[self.state])


def bright(string):
return wrap(string, Style.BRIGHT)

Expand All @@ -31,7 +89,8 @@ def wrap_header(string):


def colorize(value, warning, error):
return wrap(value, Fore.RED if value >= error else YELLOW if value >= warning else Fore.RESET)
""" Wrapper for Metric class for backward compatibility """
return Metric().init_raw(value, warning, error).colorize()


def wrap(word, color):
Expand Down
18 changes: 14 additions & 4 deletions netutils_linux_monitoring/irqtop.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@
from six.moves import xrange

from netutils_linux_monitoring.base_top import BaseTop
from netutils_linux_monitoring.colors import colorize_cpu_list, colorize
from netutils_linux_monitoring.colors import colorize_cpu_list, Metric, State
from netutils_linux_monitoring.layout import make_table
from netutils_linux_monitoring.numa import Numa


class IrqPerCpu(Metric):
warning = 40000
error = 80000


class IrqTop(BaseTop):
""" Utility for monitoring hardware interrupts distribution """
diff_total = None
irq_warning = 40000
irq_error = 80000

def __init__(self, numa=None):
BaseTop.__init__(self)
Expand Down Expand Up @@ -69,10 +72,17 @@ def make_rows(self):
output_lines.append(line)
return output_lines, cpu_count

def colorize_irq_per_cpu(self, irq_per_cpu):
""" :returns: highlighted by warning/error irq string """
metric = IrqPerCpu().init(irq_per_cpu)
if metric.state != State.OK:
self.state = metric.state
return metric.colorize()

def __repr__(self):
output_lines, cpu_count = self.make_rows()
align_map = self.make_align_map(cpu_count)
output_lines.insert(1, [colorize(irq, self.irq_warning, self.irq_error) for irq in self.diff_total] + ['TOTAL'])
output_lines.insert(1, [self.colorize_irq_per_cpu(irq) for irq in self.diff_total] + ['TOTAL'])
output_lines.insert(2, [''] * (cpu_count + 1))
table = make_table(output_lines[0], align_map, output_lines[1:])
return self.__repr_table__(table)
Expand Down
10 changes: 2 additions & 8 deletions netutils_linux_monitoring/link_rate.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from random import randint
from re import match

from six import print_, iteritems
from six import iteritems

from netutils_linux_monitoring.base_top import BaseTop
from netutils_linux_monitoring.colors import wrap, COLORS_NODE, colorize
Expand Down Expand Up @@ -73,9 +73,7 @@ def make_header(self):

@staticmethod
def colorize_stat(stat, value):
if 'errors' in stat.filename or 'dropped' in stat.filename:
return colorize(value, 1, 1)
return value
return colorize(value, 1, 1) if 'errors' in stat.filename or 'dropped' in stat.filename else value

def colorize_stats(self, dev, repr_source):
return [self.colorize_stat(stat, repr_source[dev][stat]) for stat in self.stats]
Expand Down Expand Up @@ -169,7 +167,3 @@ def unit_change(self):
self.stats[i] = Stat(stat.filename, stat.shortname.replace('bytes', 'kbits'))
elif self.options.mbits:
self.stats[i] = Stat(stat.filename, stat.shortname.replace('bytes', 'mbits'))


if __name__ == '__main__':
print_(LinkRateTop().run())
74 changes: 36 additions & 38 deletions netutils_linux_monitoring/network_top.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from netutils_linux_monitoring import IrqTop, Softirqs, SoftnetStatTop, LinkRateTop
from netutils_linux_monitoring.base_top import BaseTop
from netutils_linux_monitoring.colors import cpu_color, wrap, colorize, wrap_header, bright
from netutils_linux_monitoring.colors import cpu_color, wrap, wrap_header, bright
from netutils_linux_monitoring.layout import make_table
from netutils_linux_monitoring.numa import Numa

Expand Down Expand Up @@ -46,6 +46,32 @@ def tick(self):
_top.tick()
self.eval()

def __repr__(self):
output = [
BaseTop.header,
self.__repr_irq(),
self.__repr_cpu(),
self.__repr_dev(),
]
if not self.options.clear:
del output[0]
return "\n".join(output)

def parse_options(self):
""" Tricky way to gather all options in one util without conflicts, parse them and do some logic after parse """
parser = OptionParser()
for top in itervalues(self.tops):
for opt in top.specific_options:
try:
parser.add_option(opt)
except OptionConflictError:
pass # I don't know how to make a set of options
self.options, _ = parser.parse_args()
for top in itervalues(self.tops):
top.options = self.options
if hasattr(top, 'post_optparse'):
top.post_optparse()

def __repr_dev(self):
top = self.tops.get('link-rate')
table = make_table(top.make_header(), top.align_map, top.make_rows())
Expand Down Expand Up @@ -80,45 +106,17 @@ def __repr_cpu(self):
return wrap_header("Load per cpu:") + str(table)

def __repr_cpu_make_rows(self, irqtop, network_output, softirq_top, softnet_stat_top):
rows = [
return [
[
wrap("CPU{0}".format(stat.cpu), cpu_color(stat.cpu, self.numa)),
colorize(irq, irqtop.irq_warning, irqtop.irq_error),
colorize(softirq_rx, softirq_top.net_rx_warning, softirq_top.net_rx_error),
colorize(softirq_tx, softirq_top.net_tx_warning, softirq_top.net_tx_error),
colorize(stat.total, softnet_stat_top.total_warning, softnet_stat_top.total_error),
colorize(stat.dropped, softnet_stat_top.dropped_warning, softnet_stat_top.dropped_error),
colorize(stat.time_squeeze, softnet_stat_top.time_squeeze_warning, softnet_stat_top.time_squeeze_error),
colorize(stat.cpu_collision, softnet_stat_top.cpu_collision_warning,
softnet_stat_top.cpu_collision_error),
irqtop.colorize_irq_per_cpu(irq),
softirq_top.colorize_net_rx(net_rx),
softirq_top.colorize_net_tx(net_tx),
softnet_stat_top.colorize_total(stat.total),
softnet_stat_top.colorize_dropped(stat.dropped),
softnet_stat_top.colorize_time_squeeze(stat.time_squeeze),
softnet_stat_top.colorize_cpu_collision(stat.cpu_collision),
stat.received_rps
]
for irq, softirq_rx, softirq_tx, stat in network_output
for irq, net_rx, net_tx, stat in network_output
]
return rows

def __repr__(self):
output = [
BaseTop.header,
self.__repr_irq(),
self.__repr_cpu(),
self.__repr_dev(),
]
if not self.options.clear:
del output[0]
return "\n".join(output)

def parse_options(self):
""" Tricky way to gather all options in one util without conflicts, parse them and do some logic after parse """
parser = OptionParser()
for top in itervalues(self.tops):
for opt in top.specific_options:
try:
parser.add_option(opt)
except OptionConflictError:
pass # I don't know how to make a set of options
self.options, _ = parser.parse_args()
for top in itervalues(self.tops):
top.options = self.options
if hasattr(top, 'post_optparse'):
top.post_optparse()
28 changes: 17 additions & 11 deletions netutils_linux_monitoring/softirqs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,14 @@
from six import iteritems

from netutils_linux_monitoring.base_top import BaseTop
from netutils_linux_monitoring.colors import wrap, cpu_color
from netutils_linux_monitoring.colors import wrap, cpu_color, colorize
from netutils_linux_monitoring.layout import make_table
from netutils_linux_monitoring.numa import Numa


class Softirqs(BaseTop):
""" Utility for monitoring software interrupts distribution """

net_rx_warning = 40000
net_rx_error = 80000
net_tx_warning = 20000
net_tx_error = 30000

def __init__(self, numa=None):
BaseTop.__init__(self)
specific_options = [
Expand All @@ -34,10 +29,6 @@ def parse(self):
metrics = [line.strip().split(':') for line in softirq_file.readlines() if ':' in line]
return dict((k, [int(d) for d in v.strip().split()]) for k, v in metrics)

@staticmethod
def __active_cpu_count__(data):
return len([metric for metric in data.get('TIMER') if metric > 0])

def eval(self):
self.diff = dict((key, self.list_diff(
data, self.previous[key])) for key, data in iteritems(self.current))
Expand All @@ -48,7 +39,22 @@ def __repr__(self):
net_rx = self.repr_source().get('NET_RX')[:active_cpu_count]
net_tx = self.repr_source().get('NET_TX')[:active_cpu_count]
rows = [
[wrap("CPU{0}".format(n), cpu_color(n, self.numa)), v[0], v[1]] for n, v in enumerate(zip(net_rx, net_tx))
[wrap("CPU{0}".format(n), cpu_color(n, self.numa)), self.colorize_net_rx(v[0]), self.colorize_net_tx(v[1])]
for n, v in enumerate(zip(net_rx, net_tx))
]
table = make_table(header, ['l', 'r', 'r'], rows)
return self.__repr_table__(table)

@staticmethod
def colorize_net_rx(net_rx):
""" :returns: highlighted by warning/error net_rx string """
return colorize(net_rx, 40000, 80000)

@staticmethod
def colorize_net_tx(net_tx):
""" :returns: highlighted by warning/error net_tx string """
return colorize(net_tx, 20000, 30000)

@staticmethod
def __active_cpu_count__(data):
return len([metric for metric in data.get('TIMER') if metric > 0])
35 changes: 28 additions & 7 deletions netutils_linux_monitoring/softnet_stat.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# coding=utf-8
from optparse import Option
from random import randint

Expand Down Expand Up @@ -81,20 +82,40 @@ def parse(self):
def eval(self):
self.diff = [data - self.previous[cpu] for cpu, data in enumerate(self.current)]

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

@staticmethod
def make_header():
return ["CPU", "total", "dropped", "time_squeeze", "cpu_collision", "received_rps"]

def make_rows(self):
return [[
wrap("CPU{0}".format(stat.cpu), cpu_color(stat.cpu, self.numa)),
colorize(stat.total, self.total_warning, self.total_error),
colorize(stat.dropped, self.dropped_warning, self.dropped_error),
colorize(stat.time_squeeze, self.time_squeeze_warning, self.time_squeeze_error),
colorize(stat.cpu_collision, self.cpu_collision_warning, self.cpu_collision_error),
self.colorize_total(stat.total),
self.colorize_dropped(stat.dropped),
self.colorize_time_squeeze(stat.time_squeeze),
self.colorize_cpu_collision(stat.cpu_collision),
stat.received_rps
] for stat in self.repr_source()]

def __repr__(self):
table = make_table(self.make_header(), self.align, list(self.make_rows()))
return self.__repr_table__(table)
@staticmethod
def colorize_total(total):
""" :returns: highlighted by warning/error total string """
return colorize(total, 300000, 900000)

@staticmethod
def colorize_dropped(dropped):
""" :returns: highlighted by warning/error dropped string """
return colorize(dropped, 1, 1)

@staticmethod
def colorize_time_squeeze(time_squeeze):
""" :returns: highlighted by warning/error time_squeeze string """
return colorize(time_squeeze, 1, 300)

@staticmethod
def colorize_cpu_collision(cpu_collision):
""" :returns: highlighted by warning/error cpu_collision string """
return colorize(cpu_collision, 1, 1000)