glances_diskio.py 5.4 KB
Newer Older
A
Alessio Sergi 已提交
1 2
# -*- coding: utf-8 -*-
#
3
# This file is part of Glances.
A
Alessio Sergi 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#
# Copyright (C) 2014 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/>.
19
"""
20
Glances DiskIO plugin
21
"""
A
Alessio Sergi 已提交
22

A
Alessio Sergi 已提交
23
import psutil
A
Alessio Sergi 已提交
24

25
# Import Glances libs
A
Alessio Sergi 已提交
26
from glances.core.glances_timer import getTimeSinceLastUpdate
A
Alessio Sergi 已提交
27
from glances.plugins.glances_plugin import GlancesPlugin
A
Alessio Sergi 已提交
28 29 30 31 32 33 34 35 36


class Plugin(GlancesPlugin):
    """
    Glances's disks IO Plugin

    stats is a list
    """

37 38
    def __init__(self, args=None):
        GlancesPlugin.__init__(self, args=args)
A
Alessio Sergi 已提交
39 40 41 42 43 44 45 46 47 48

        # We want to display the stat in the curse interface
        self.display_curse = True
        # Set the message position
        # It is NOT the curse position but the Glances column/line
        # Enter -1 to right align
        self.column_curse = 0
        # Enter -1 to diplay bottom
        self.line_curse = 3

49
        # Init the stats
A
Alessio Sergi 已提交
50
        self.reset()
51

52
    def reset(self):
A
Alessio Sergi 已提交
53
        """
54
        Reset/init the stats
A
Alessio Sergi 已提交
55
        """
56
        self.stats = []
A
Alessio Sergi 已提交
57

58
    def update(self):
59 60 61 62 63 64 65
        """
        Update disk IO stats using the input method
        """

        # Reset stats
        self.reset()

66
        if self.get_input() == 'local':
67 68 69 70 71 72 73 74
            # Update stats using the standard system lib
            # Grab the stat using the PsUtil disk_io_counters method
            # read_count: number of reads
            # write_count: number of writes
            # read_bytes: number of bytes read
            # write_bytes: number of bytes written
            # read_time: time spent reading from disk (in milliseconds)
            # write_time: time spent writing to disk (in milliseconds)
N
Nicolargo 已提交
75 76 77 78
            try:
                diskiocounters = psutil.disk_io_counters(perdisk=True)
            except:
                return self.stats
79 80

            # Previous disk IO stats are stored in the diskio_old variable
N
Nicolargo 已提交
81
            if not hasattr(self, 'diskio_old'):
82
                # First call, we init the network_old var
A
Alessio Sergi 已提交
83
                try:
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
                    self.diskio_old = diskiocounters
                except (IOError, UnboundLocalError):
                    pass
            else:
                # By storing time data we enable Rx/s and Tx/s calculations in the
                # XML/RPC API, which would otherwise be overly difficult work
                # for users of the API
                time_since_update = getTimeSinceLastUpdate('disk')

                diskio_new = diskiocounters
                for disk in diskio_new:
                    try:
                        # Try necessary to manage dynamic disk creation/del
                        diskstat = {}
                        diskstat['time_since_update'] = time_since_update
                        diskstat['disk_name'] = disk
                        diskstat['read_bytes'] = (
                            diskio_new[disk].read_bytes -
                            self.diskio_old[disk].read_bytes)
                        diskstat['write_bytes'] = (
                            diskio_new[disk].write_bytes -
                            self.diskio_old[disk].write_bytes)
                    except KeyError:
                        continue
                    else:
                        self.stats.append(diskstat)
A
Alessio Sergi 已提交
110

N
Nicolargo 已提交
111
                # Save stats to compute next bitrate
112
                self.diskio_old = diskio_new
113
        elif self.get_input() == 'snmp':
114
            # Update stats using SNMP
115
            # No standard way for the moment...
116
            pass
A
Alessio Sergi 已提交
117

118
        return self.stats
A
Alessio Sergi 已提交
119 120 121 122 123

    def msg_curse(self, args=None):
        """
        Return the dict to display in the curse interface
        """
124

A
Alessio Sergi 已提交
125 126 127
        # Init the return message
        ret = []

128
        # Only process if stats exist and display plugin enable...
129
        if self.stats == [] or args.disable_diskio:
130 131
            return ret

A
Alessio Sergi 已提交
132 133
        # Build the string message
        # Header
134
        msg = "{0:9}".format(_("DISK I/O"))
A
Alessio Sergi 已提交
135
        ret.append(self.curse_add_line(msg, "TITLE"))
136
        msg = "{0:>7}".format(_("R/s"))
A
Alessio Sergi 已提交
137
        ret.append(self.curse_add_line(msg))
138
        msg = "{0:>7}".format(_("W/s"))
A
Alessio Sergi 已提交
139 140 141
        ret.append(self.curse_add_line(msg))
        # Disk list (sorted by name)
        for i in sorted(self.stats, key=lambda diskio: diskio['disk_name']):
142
            # Do not display hidden interfaces
143
            if self.is_hide(i['disk_name']):
144
                continue
A
Alessio Sergi 已提交
145 146
            # New line
            ret.append(self.curse_new_line())
147
            msg = "{0:9}".format(i['disk_name'])
A
Alessio Sergi 已提交
148 149
            ret.append(self.curse_add_line(msg))
            txps = self.auto_unit(int(i['read_bytes'] // i['time_since_update']))
150
            rxps = self.auto_unit(int(i['write_bytes'] // i['time_since_update']))
151
            msg = "{0:>7}".format(txps)
A
Alessio Sergi 已提交
152
            ret.append(self.curse_add_line(msg))
153
            msg = "{0:>7}".format(rxps)
154
            ret.append(self.curse_add_line(msg))
A
Alessio Sergi 已提交
155 156

        return ret