DiskSpace   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 75
Duplicated Lines 0 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
wmc 10
c 3
b 1
f 0
dl 0
loc 75
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A proc_mounts() 0 18 4
A poll() 0 21 2
B __init__() 0 23 4
1
# -*- coding: utf-8 -*-
2
"""Disk usage metrics reader from /proc on Linux."""
3
import re
4
import os
5
import sys
6
import plumd
7
from plumd.util import get_file_list
8
9
PY3 = sys.version_info > (3,)
10
11
__author__ = 'Kenny Freeman'
12
__email__ = '[email protected]'
13
__license__ = "ISCL"
14
__docformat__ = 'reStructuredText'
15
16
17
class DiskSpace(plumd.Reader):
18
    """Plugin to measure disk usage."""
19
20
    # default config values
21
    defaults = {
22
        'poll.interval': 60,
23
        'fs_types': ['xfs', 'ext2', 'ext3', 'ext4'],
24
        'mnt_exclude_re': "^\/mnt\/.*",
0 ignored issues
show
Bug introduced by
A suspicious escape sequence \/ was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

Loading history...
25
        'chrs_keep': 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-'
26
    }
27
28
    def __init__(self, log, config):
29
        """Plugin to measure disk usage.
30
31
        :param log: A logger
32
        :type log: logging.RootLogger
33
        :param config: a plumd.config.Conf configuration helper instance.
34
        :type config: plumd.config.Conf
35
        """
36
        super(DiskSpace, self).__init__(log, config)
37
        self.config.defaults(DiskSpace.defaults)
38
        # skip mounts for devices matching this re
39
        self.mnt_re = re.compile(config.get('mnt_exclude_re'))
40
41
        # characters to remove from device names
42
        self.filter_chars = "".join(char for char in map(chr, range(256))
43
                                    if char not in self.config.get('chrs_keep'))
44
        # args for str.translate() calls
45
        self.tlate_args = [None, self.filter_chars]
46
        if PY3:
47
            self.tlate_args = [dict.fromkeys(
48
                map(ord, self.filter_chars)), None]
49
        # get a list of mount points - only on init
50
        self.mounts = self.proc_mounts()
51
52
    def proc_mounts(self):
53
        """Return a list of mounted file systems.
54
55
        :rtype: list
56
        """
57
        fs_types = self.config.get('fs_types')
58
        ret = []
59
        mounts = get_file_list("/proc/mounts")
60
        mnt_re = self.mnt_re
61
        tlate_args = self.tlate_args
62
        for entry in mounts:
63
            dev, path, f_sys, _, _, _ = entry.split()
64
            if mnt_re.match(path) or f_sys not in fs_types:
65
                continue
66
            dev = re.sub("^/dev/", "", dev)
67
            dev = dev.translate(*tlate_args)
0 ignored issues
show
Coding Style introduced by
Usage of * or ** arguments should usually be done with care.

Generally, there is nothing wrong with usage of * or ** arguments. For readability of the code base, we suggest to not over-use these language constructs though.

For more information, we can recommend this blog post from Ned Batchelder including its comments which also touches this aspect.

Loading history...
68
            ret.append((dev, path))
69
        return ret
70
71
    def poll(self):
72
        """Poll for disk space usage.
73
74
        :rtype: ResultSet
75
        """
76
        result = plumd.Result("diskusage")
77
        for dev, mpoint in self.mounts:
78
            mp_stat = os.statvfs(mpoint)
79
            free = (mp_stat.f_bavail * mp_stat.f_frsize)
80
            total = (mp_stat.f_blocks * mp_stat.f_frsize)
81
            used = (mp_stat.f_blocks - mp_stat.f_bfree) * mp_stat.f_frsize
82
            total_inodes = mp_stat.f_files
83
            free_inodes = mp_stat.f_favail
84
            used_inodes = total_inodes - free_inodes
85
            result.add(plumd.Int("{0}.free".format(dev), free))
86
            result.add(plumd.Int("{0}.total".format(dev), total))
87
            result.add(plumd.Int("{0}.used".format(dev), used))
88
            result.add(plumd.Int("{0}.total_inodes".format(dev), total_inodes))
89
            result.add(plumd.Int("{0}.free_inodes".format(dev), free_inodes))
90
            result.add(plumd.Int("{0}.used_inodes".format(dev), used_inodes))
91
        return plumd.ResultSet([result])
92