NetDev   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 111
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 14
c 2
b 0
f 0
dl 0
loc 111
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __init__() 0 15 1
A poll() 0 6 1
B get_columns() 0 36 6
B check() 0 36 6
1
# -*- coding: utf-8 -*-
2
"""Network interface metrics reader for /proc on Linux."""
3
import re
4
import time
5
from collections import deque
6
7
import plumd
8
from plumd.util import Differential
9
from plumd.util import get_file
10
11
__author__ = 'Kenny Freeman'
12
__email__ = '[email protected]'
13
__license__ = "ISCL"
14
__docformat__ = 'reStructuredText'
15
16
17
class NetDev(plumd.Reader):
18
    """Plugin to measure various kernel metrics from /proc."""
19
20
    rename = {
21
        'packets': 'pkt',
22
        'compressed': 'compr',
23
        'multicast': 'mcast',
24
    }
25
26
    defaults = {
27
        'poll.interval': 10,
28
        'proc_path': '/proc',
29
        'proc_netdev_re': "(virbr\d+)|(vnet\d+)"
0 ignored issues
show
Bug introduced by
A suspicious escape sequence \d 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...
30
    }
31
32
    def __init__(self, log, config):
33
        """Plugin to measure network interface metrics from proc file net/dev.
34
35
        :param log: A logger
36
        :type log: logging.RootLogger
37
        :param config: a plumd.config.Conf configuration helper instance.
38
        :type config: plumd.config.Conf
39
        """
40
        super(NetDev, self).__init__(log, config)
41
        config.defaults(NetDev.defaults)
42
        self.proc_file = "{0}/net/dev".format(config.get('proc_path'))
43
        self.dev_re = re.compile(config.get('proc_netdev_re'))
44
        self.calc = Differential()
45
        self.enabled = True
46
        self.dev_cols = self.get_columns()
47
48
    def get_columns(self):
49
        """Return the /proc file column names.
50
51
        :rtype: list
52
        """
53
        cols = []
54
        dat = get_file(self.proc_file)
55
        lines = deque(dat.split("\n"))
56
        nlines = len(lines)
57
        # expect at least one network interface + 2 header lines
58
        if nlines < 2:
59
            msg = "NetDev: cannot parse {0}"
60
            self.log.error(msg.format(self.proc_file))
61
            self.enabled = False
62
            return cols
63
64
        # skip first line eg. Inter-|   Receive
65
        lines.popleft()
66
        # next line has the header values
67
        hdr_vals = deque(lines.popleft().split("|"))
68
        # remove eg.  face
69
        hdr_vals.popleft()
70
        if len(hdr_vals) != 2:
71
            msg = "NetDev: cannot parse {0}"
72
            self.log.error(msg.format(self.proc_file))
73
            self.enabled = False
74
            return cols
75
76
        # values are receive then transmit
77
        hdrs = dict(zip(["rx", "tx"], hdr_vals))
78
        for pfx, metrics in hdrs.items():
79
            for metric in metrics.split():
80
                if metric in NetDev.rename:
81
                    metric = NetDev.rename[metric]
82
                cols.append("{0}_{1}".format(pfx, metric))
83
        return cols
84
85
    def poll(self):
86
        """Return network interface metrics from proc file net/dev.
87
88
        :rtype: ResultSet
89
        """
90
        return plumd.ResultSet(self.check())
91
92
    def check(self):
93
        """Return network interface metrics from proc file net/dev.
94
95
        :rtype: list
96
        """
97
        result = plumd.Result("netdev")
98
        if not self.enabled:
99
            return [result]
100
101
        dat = {}
102
        cols = self.dev_cols
103
        regexp = self.dev_re
104
105
        # read and process /proc/net/dev
106
        with open(self.proc_file, 'r') as pfd:
107
            lines = deque(pfd.read().strip().split("\n"))
108
            # remove the two header lines - format fail :|
109
            lines.popleft()
110
            lines.popleft()
111
112
        # for Differential
113
        times = time.time()
114
115
        # now it's dev, metrics
116
        for line in lines:
117
            dat = line.split()
118
            dev = dat[0].split(":")[0]
119
            vals = dat[1:]
120
            if regexp.match(dev):
121
                continue
122
            for key, val in dict(zip(cols, vals)).items():
123
                mstr = "{0}.{1}".format(dev, key)
124
                dval = self.calc.per_second(mstr, int(val), times)
125
                result.add(plumd.Float(mstr, dval))
126
127
        return [result]
128