Added irq monitoring plugin

This commit is contained in:
angelopoerio 2016-08-19 19:26:23 +02:00
parent aa94ccb91a
commit e7fafdbdee
15 changed files with 201 additions and 7 deletions

View File

@ -120,6 +120,8 @@ Start the client browser (browser mode):\n\
dest='disable_ip', help='disable IP module')
parser.add_argument('--disable-diskio', action='store_true', default=False,
dest='disable_diskio', help='disable disk I/O module')
parser.add_argument('--disable-irq', action='store_true', default=False,
dest='disable_irq', help='disable IRQ module'),
parser.add_argument('--disable-fs', action='store_true', default=False,
dest='disable_fs', help='disable filesystem module')
parser.add_argument('--disable-folder', action='store_true', default=False,

View File

@ -361,7 +361,9 @@ class _GlancesCurses(object):
elif self.pressedkey == ord('d'):
# 'd' > Show/hide disk I/O stats
self.args.disable_diskio = not self.args.disable_diskio
elif self.pressedkey == ord('D'):
elif self.pressedkey == ord('R'):
self.args.disable_irq = not self.args.disable_irq
elif self.pressedkey == ord('D'):
# 'D' > Show/hide Docker stats
self.args.disable_docker = not self.args.disable_docker
elif self.pressedkey == ord('e'):
@ -537,7 +539,9 @@ class _GlancesCurses(object):
stats_memswap = stats.get_plugin('memswap').get_stats_display(args=self.args)
stats_network = stats.get_plugin('network').get_stats_display(
args=self.args, max_width=plugin_max_width)
try:
stats_irq = stats.get_plugin('irq').get_stats_display(
args=self.args, max_width=plugin_max_width)
try:
stats_ip = stats.get_plugin('ip').get_stats_display(args=self.args)
except AttributeError:
stats_ip = None
@ -728,6 +732,8 @@ class _GlancesCurses(object):
self.new_line()
self.display_plugin(stats_fs)
self.new_line()
self.display_plugin(stats_irq)
self.new_line()
self.display_plugin(stats_folders)
self.new_line()
self.display_plugin(stats_raid)
@ -735,6 +741,7 @@ class _GlancesCurses(object):
self.display_plugin(stats_sensors)
self.new_line()
self.display_plugin(stats_now)
self.new_line()
# ====================================
# Display right stats (process and co)

View File

@ -56,7 +56,7 @@
</div>
<div class="row">
<div class="col-sm-12 col-lg-6">{{help.enable_disable_process_stats}}</div>
<div class="col-sm-12 col-lg-6"></div>
<div class="col-sm-12 col-lg-6">{{help.show_hide_irq}}</div>
</div>
<div class="row">
<div class="col-sm-12 col-lg-6">{{help.enable_disable_quick_look}}</div>

View File

@ -24,6 +24,7 @@
<script type="text/javascript" src="services/plugins/glances_alert.js"></script>
<script type="text/javascript" src="services/plugins/glances_cpu.js"></script>
<script type="text/javascript" src="services/plugins/glances_diskio.js"></script>
<script type="text/javascript" src="services/plugins/glances_irq.js"></script>
<script type="text/javascript" src="services/plugins/glances_docker.js"></script>
<script type="text/javascript" src="services/plugins/glances_fs.js"></script>
<script type="text/javascript" src="services/plugins/glances_folders.js"></script>

View File

@ -0,0 +1,8 @@
<div class="table-row">
<div class="table-cell text-left title">IRQ</div>
<div class="table-cell">Rate/s</div>
</div>
<div class="table-row" ng-repeat="irq in statsIrq.irqs">
<div class="table-cell text-left">{{irq.irq_line}}</div>
<div class="table-cell">{{irq.irq_rate}}</div>
</div>

View File

@ -48,6 +48,9 @@
<section id="network" class="plugin table-row-group" ng-show="!arguments.disable_network" ng-include src="'plugins/network.html'"></section>
<section id="ports" class="plugin table-row-group" ng-show="!arguments.disable_ports" ng-include src="'plugins/ports.html'"></section>
<section id="diskio" class="plugin table-row-group" ng-show="!arguments.disable_diskio && statsDiskio.disks.length > 0" ng-include src="'plugins/diskio.html'"></section>
<section id="irq" class="plugin table-row-group" ng-show="!arguments.disable_irq" ng-include src="'plugins/irq.html'"></section>
<section id="fs" class="plugin table-row-group" ng-show="!arguments.disable_fs" ng-include src="'plugins/fs.html'"></section>
<section id="folders" class="plugin table-row-group" ng-show="!arguments.disable_fs && statsFolders.folders.length > 0" ng-include src="'plugins/folders.html'"></section>
<section id="raid" class="plugin table-row-group" ng-show="statsRaid.hasDisks()" ng-include src="'plugins/raid.html'"></section>

View File

@ -5,6 +5,7 @@ glancesApp.service('GlancesStats', function($http, $injector, $q, GlancesPlugin)
'alert': 'GlancesPluginAlert',
'cpu': 'GlancesPluginCpu',
'diskio': 'GlancesPluginDiskio',
'irq' : 'GlancesPluginIrq',
'docker': 'GlancesPluginDocker',
'ip': 'GlancesPluginIp',
'fs': 'GlancesPluginFs',

View File

@ -0,0 +1,21 @@
glancesApp.service('GlancesPluginIrq', function($filter) {
var _pluginName = "irq";
this.irqs = [];
this.setData = function(data, views) {
data = data[_pluginName];
this.irqs = [];
for (var i = 0; i < data.length; i++) {
var IrqData = data[i];
var timeSinceUpdate = IrqData['time_since_update'];
var irq = {
'irq_line': IrqData['irq_line'],
'irq_rate': IrqData['irq_rate']
};
this.irqs.push(irq);
}
};
});

View File

@ -24,6 +24,7 @@ glancesApp.controller('statsController', function ($scope, $rootScope, $interval
$scope.statsAlert = GlancesStats.getPlugin('alert');
$scope.statsCpu = GlancesStats.getPlugin('cpu');
$scope.statsDiskio = GlancesStats.getPlugin('diskio');
$scope.statsIrq = GlancesStats.getPlugin('irq');
$scope.statsDocker = GlancesStats.getPlugin('docker');
$scope.statsFs = GlancesStats.getPlugin('fs');
$scope.statsFolders = GlancesStats.getPlugin('folders');
@ -103,6 +104,10 @@ glancesApp.controller('statsController', function ($scope, $rootScope, $interval
// d => Show/hide disk I/O stats
$scope.arguments.disable_diskio = !$scope.arguments.disable_diskio;
break;
case $event.shiftKey && $event.keyCode == keycodes.R:
// R => Show/hide IRQ
$scope.arguments.disable_irq = !$scope.arguments.disable_irq;
break;
case !$event.shiftKey && $event.keyCode == keycodes.f:
// f => Show/hide filesystem stats
$scope.arguments.disable_fs = !$scope.arguments.disable_fs;

View File

@ -29,5 +29,6 @@ var keycodes = {
'g' : '71',
'r' : '82',
'q' : '81',
'A' : '65'
'A' : '65',
'R' : '82',
}

View File

@ -74,7 +74,8 @@ class Plugin(GlancesPlugin):
self.view_data['sort_cpu_times'] = msg_col.format('t', 'Sort processes by TIME')
self.view_data['show_hide_help'] = msg_col2.format('h', 'Show/hide this help screen')
self.view_data['show_hide_diskio'] = msg_col.format('d', 'Show/hide disk I/O stats')
self.view_data['view_network_io_combination'] = msg_col2.format('T', 'View network I/O as combination')
self.view_data['show_hide_irq'] = msg_col2.format('R', 'Show/hide IRQ stats')
self.view_data['view_network_io_combination'] = msg_col2.format('T', 'View network I/O as combination')
self.view_data['show_hide_filesystem'] = msg_col.format('f', 'Show/hide filesystem stats')
self.view_data['view_cumulative_network'] = msg_col2.format('U', 'View cumulative network I/O')
self.view_data['show_hide_network'] = msg_col.format('n', 'Show/hide network stats')
@ -172,6 +173,7 @@ class Plugin(GlancesPlugin):
ret.append(self.curse_add_line(self.view_data['quit']))
ret.append(self.curse_new_line())
ret.append(self.curse_add_line(self.view_data['enable_disable_ports']))
ret.append(self.curse_add_line(self.view_data['show_hide_irq']))
ret.append(self.curse_new_line())
ret.append(self.curse_new_line())

View File

@ -0,0 +1,127 @@
# -*- coding: utf-8 -*-
#
# This file is part of Glances.
#
# Copyright (C) 2015 Nicolargo <nicolas@nicolargo.com>
#
# Glances 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.
#
# Glances 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 <http://www.gnu.org/licenses/>.
"""IRQ plugin."""
import operator
from glances.timer import getTimeSinceLastUpdate
from glances.plugins.glances_plugin import GlancesPlugin
class Plugin(GlancesPlugin):
"""Glances IRQ plugin.
stats is a list
"""
def __init__(self, args=None):
"""Init the plugin."""
super(Plugin, self).__init__(args=args)
# We want to display the stat in the curse interface
self.display_curse = True
self.lasts = {}
# Init the stats
self.reset()
def get_key(self):
"""Return the key of the list."""
return 'irq_line'
def reset(self):
"""Reset/init the stats."""
self.stats = []
@GlancesPlugin._log_result_decorator
def update(self):
"""Update the IRQ stats"""
# Reset the list
self.reset()
if self.input_method == 'local':
with open('/proc/interrupts') as irq_proc:
time_since_update = getTimeSinceLastUpdate('irq')
irq_proc.readline() # skip header line
for irq_line in irq_proc.readlines():
splitted_line = irq_line.split()
irq_line = splitted_line[0].replace(':','')
current_irqs = sum([int(count) for count in splitted_line[1:] if count.isdigit()]) # sum interrupts on all CPUs
irq_rate = int(current_irqs - self.lasts.get(irq_line) if self.lasts.get(irq_line) else 0 // time_since_update)
irq_current = {
'irq_line': irq_line,
'irq_rate': irq_rate,
'key': self.get_key(),
'time_since_update': time_since_update
}
self.stats.append(irq_current)
self.lasts[irq_line] = current_irqs
elif self.input_method == 'snmp':
# not available
pass
# Update the view
self.update_views()
self.stats = sorted(self.stats, key=operator.itemgetter('irq_rate'), reverse=True)[:5] # top 5 IRQ by rate/s
return self.stats
def update_views(self):
"""Update stats views."""
# Call the father's method
super(Plugin, self).update_views()
def msg_curse(self, args=None, max_width=None):
"""Return the dict to display in the curse interface."""
# Init the return message
ret = []
# Only process if stats exist and display plugin enable...
if not self.stats or args.disable_irq:
return ret
# Max size for the fsname name
if max_width is not None and max_width >= 23:
# Interface size name = max_width - space for interfaces bitrate
irq_max_width = max_width - 14
else:
irq_max_width = 9
# Build the string message
# Header
msg = '{:{width}}'.format('IRQ', width=irq_max_width)
ret.append(self.curse_add_line(msg, "TITLE"))
msg = '{:>7}'.format('Rate/s')
ret.append(self.curse_add_line(msg))
# Filesystem list (sorted by name)
for i in self.stats:
# New line
ret.append(self.curse_new_line())
msg = '{:>3}'.format(i['irq_line'])
ret.append(self.curse_add_line(msg))
msg = '{:>12}'.format(str(i['irq_rate']))
ret.append(self.curse_add_line(msg))
return ret

View File

@ -94,7 +94,7 @@ class TestGlances(unittest.TestCase):
if p in ('uptime', 'now'):
self.assertIsInstance(req.json(), text_type)
elif p in ('fs', 'percpu', 'sensors', 'alert', 'processlist', 'diskio',
'hddtemp', 'batpercent', 'network', 'folders', 'amps', 'ports'):
'hddtemp', 'batpercent', 'network', 'folders', 'amps', 'ports', 'irq'):
self.assertIsInstance(req.json(), list)
elif p in ('psutilversion', 'help'):
pass

View File

@ -175,6 +175,14 @@ class TestGlances(unittest.TestCase):
self.assertIsInstance(req, dict)
self.assertIsInstance(req['cpu'], dict)
def test_012_irq(self):
"""IRQS"""
method = "getIrqs()"
print('INFO: [TEST_012] Method: %s' % method)
req = json.loads(client.getIrq())
self.assertIsInstance(req, list)
def test_999_stop_server(self):
"""Stop the Glances Web Server."""
print('INFO: [TEST_999] Stop the Glances Server')

View File

@ -76,7 +76,7 @@ class TestGlances(unittest.TestCase):
def test_001_plugins(self):
"""Check mandatory plugins."""
plugins_to_check = ['system', 'cpu', 'load', 'mem', 'memswap', 'network', 'diskio', 'fs']
plugins_to_check = ['system', 'cpu', 'load', 'mem', 'memswap', 'network', 'diskio', 'fs', 'irq']
print('INFO: [TEST_001] Check the mandatory plugins list: %s' % ', '.join(plugins_to_check))
plugins_list = stats.getAllPlugins()
for plugin in plugins_to_check:
@ -193,6 +193,14 @@ class TestGlances(unittest.TestCase):
self.assertTrue(type(stats_grab) is dict, msg='IP stats is not a dict')
print('INFO: IP stats: %s' % stats_grab)
def test_013_irq(self):
"""Check IRQ plugin."""
print('INFO: [TEST_013] Check IRQ stats')
stats_grab = stats.get_plugin('irq').get_raw()
self.assertTrue(type(stats_grab) is list, msg='IRQ stats is not a list')
print('INFO: IRQ stats: %s' % stats_grab)
def test_097_attribute(self):
"""Test GlancesAttribute classe"""
print('INFO: [TEST_097] Test attribute')