Completed
Push — master ( f1337f...ab2213 )
by Kenny
01:06
created

NetDev.get_columns()   B

Complexity

Conditions 6

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
c 0
b 0
f 0
dl 0
loc 32
rs 7.5384
1
# -*- coding: utf-8 -*-
2
3
__author__ = 'Kenny Freeman'
4
__email__ = '[email protected]'
5
__license__ = "ISCL"
6
__docformat__ = 'reStructuredText'
7
8
import re
9
import time
10
from collections import deque
11
12
import plumd
13
import plumd.plugins
14
from plumd.calc import Differential
15
from plumd.util import get_file, get_file_map
16
17
18
class NetDev(plumd.plugins.Reader):
19
    """Plugin to measure various kernel metrics from /proc."""
20
21
    rename = {
22
        'packets': 'pkt',
23
        'compressed': 'compr',
24
        'multicast': 'mcast',
25
    }
26
27
    defaults = {
28
        'poll.interval': 10,
29
        'proc_path': '/proc',
30
        'proc_netdev_re': "(virbr\d+)|(vnet\d+)"
31
    }
32
33
    def __init__(self, log, config):
34
        """Plugin to measure network interface metrics from proc file net/dev.
35
36
        :param log: A logger
37
        :type log: logging.RootLogger
38
        :param config: a plumd.config.Conf configuration helper instance.
39
        :type config: plumd.config.Conf
40
        """
41
        super(NetDev, self).__init__(log, config)
42
        config.defaults(NetDev.defaults)
43
        self.proc_file = "{0}/net/dev".format(config.get('proc_path'))
44
        self.dev_re = re.compile(config.get('proc_netdev_re'))
45
        self.calc = Differential()
46
        self.enabled = True
47
        self.dev_cols = self.get_columns()
48
49
50
    def get_columns(self):
51
        cols = []
52
        dat = get_file(self.proc_file)
53
        lines = deque(dat.split("\n"))
54
        nlines = len(lines)
55
        # expect at least one network interface + 2 header lines
56
        if nlines < 2:
57
            msg = "NetDev: cannot parse {0}"
58
            self.log.error(msg.format(self.proc_file))
59
            self.enabled = False
60
            return cols
61
62
        # skip first line eg. Inter-|   Receive
63
        lines.popleft()
64
        # next line has the header values
65
        hdr_vals = deque(lines.popleft().split("|"))
66
        # remove eg.  face
67
        hdr_vals.popleft()
68
        if len(hdr_vals) != 2:
69
            msg = "NetDev: cannot parse {0}"
70
            self.log.error(msg.format(self.proc_files))
71
            self.enabled = False
72
            return cols
73
74
        # values are receive then transmit
75
        hdrs = dict(zip(["rx", "tx"], hdr_vals))
76
        for pfx, metrics in hdrs.items():
77
            for metric in metrics.split():
78
                if metric in NetDev.rename:
79
                    metric = NetDev.rename[metric]
80
                cols.append("{0}_{1}".format(pfx, metric))
81
        return cols
82
83
84
    def poll(self):
85
        """Return network interface metrics from proc file net/dev.
86
87
        :rtype: ResultSet
88
        """
89
        return plumd.ResultSet(self.check())
90
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 f:
107
            lines = deque(f.read().strip().split("\n"))
108
            # remove the two header lines - format fail :|
109
            lines.popleft()
110
            lines.popleft()
111
112
        # for Differential
113
        ts = time.time()
114
115
        # now it's dev, metrics
116
        for line in lines:
117
            dat = line.split()
118
            dev = dat[0][:-1]
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), ts)
125
                result.add(plumd.Float(mstr, dval))
126
127
        return [result]
128