Completed
Push — master ( 8451c1...a45803 )
by Kenny
01:18
created

NetSnmp.check()   D

Complexity

Conditions 10

Size

Total Lines 58

Duplication

Lines 58
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
c 1
b 0
f 0
dl 58
loc 58
rs 4.9315

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like NetSnmp.check() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
3
__author__ = 'Kenny Freeman'
4
__email__ = '[email protected]'
5
__license__ = "ISCL"
6
__docformat__ = 'reStructuredText'
7
8
import time
9
from collections import deque
10
11
import plumd
12
import plumd.plugins
13
from plumd.calc import Differential
14
from plumd.util import get_file_list, Filter
15
16
17
## todo: switch from list with pop(0) to deque
18
class NetSnmp(plumd.plugins.Reader):
19
    """Plugin to measure various kernel metrics from /proc."""
20
    defaults = {
21
        'poll.interval': 10,
22
        'proc_path': '/proc',
23
        'proc_netsnmp_record': {
24
            'Ip': [ 'Forwarding', 'InReceives', 'InHdrErrors', 'InAddrErrors',
25
                    'ForwDatagrams', 'InUnknownProtos', 'InDiscards',
26
                    'InDelivers', 'OutRequests', 'OutDiscards',
27
                    'ReasmTimeout', 'ReasmReqds', 'ReasmOKs', 'ReasmFails',
28
                    'FragOKs', 'FragFails', 'FragCreates' ],
29
            'Icmp': [ 'InMsgs','InErrors', 'InCsumErrors', 'InDestUnreachs',
30
                     'InTimeExcds', 'InParmProbs', 'InSrcQuenchs',
31
                     'InRedirects', 'InEchos', 'InEchoReps',  'OutMsgs',
32
                     'OutErrors', 'OutDestUnreachs', 'OutTimeExcds',
33
                     'OutParmProbs', 'OutSrcQuenchs', 'OutRedirects',
34
                     'OutEchos', 'OutEchoReps' ],
35
            'IcmpMsg': [ 'OutType3' ],
36
            'Tcp': [ 'MaxConn', 'ActiveOpens', 'PassiveOpens', 'AttemptFails',
37
                    'EstabResets', 'CurrEstab', 'InSegs', 'OutSegs',
38
                    'RetransSegs', 'InErrs', 'OutRsts', 'InCsumErrors' ],
39
            'Udp': [ 'InDatagrams', 'NoPorts', 'InErrors', 'OutDatagrams',
40
                    'RcvbufErrors', 'SndbufErrors', 'InCsumErrors' ]
41
        }
42
    }
43
44
    def __init__(self, log, config):
45
        """Plugin to measure various kernel metrics from /proc.
46
47
        :param log: A logger
48
        :type log: logging.RootLogger
49
        :param config: a plumd.config.Conf configuration helper instance.
50
        :type config: plumd.config.Conf
51
        """
52
        super(NetSnmp, self).__init__(log, config)
53
        self.config.defaults(NetSnmp.defaults)
54
        self.calc = Differential()
55
        self.proc_file = "{0}/net/snmp".format(config.get('proc_path'))
56
        self.filter = Filter()
57
58
59
60
    def poll(self):
61
        """Poll for kernel metrics under /proc.
62
63
        :rtype: ResultSet
64
        """
65
        return plumd.ResultSet(self.check())
66
67
68 View Code Duplication
    def check(self):
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
69
        """Return network protocol metrics from proc file net/snmp.
70
71
        Add entries to the configuration value 'skip_proc_net_snmp' to skip
72
        metrics.
73
74
        Add entries to the configuration value 'net_snmp_items' to match the
75
        format/order of the proc file net/snmp entries on the system.
76
77
        :rtype: plumd.Result
78
        """
79
        record = self.config.get('proc_netsnmp_record')
80
        result = plumd.Result("net_snmp")
81
82
        # read the proc file
83
        dat = None
84
        with open(self.proc_file, 'r') as f:
85
            try:
86
                dat = f.read().strip().split("\n")
87
            except Exception as e:
88
                self.log.error("failed to read {0}".format(self.proc_file))
89
                return result
90
91
        # timestamp for Differential calculations
92
        ts = time.time()
93
94
        # should always have a header row and value row, ie. divisible by 2
95
        if len(dat) % 2 != 0:
96
            self.log.error("netsnmp: cannot parse {0}".format(self.proc_file))
97
            return result
98
99
        # split values into lists
100
        dlist = deque()
101
        for entry in dat:
102
            dlist.append(entry.split())
103
104
        # put lists into key: value dict
105
        metrics = {}
106
        while dlist:
107
            headers = dlist.popleft()
108
            values = dlist.popleft()
109
            # { 'IpExt': {'InNoRoutes': 0, ...} } - [:-1] on IpExt: removes :
110
            metrics[headers[0][:-1]] = dict(zip(headers, values))
111
112
        # now, we have a list of items to record, just need to record them
113
        for proto, mnames in record.items():
114
            if proto not in metrics:
115
                self.log.warn("netsnmp: unknown protocol: {0}".format(proto))
116
                continue
117
            values = metrics[proto]
118
            for mname in mnames:
119
                if mname in values:
120
                    mstr = "{0}.{1}".format(proto, mname)
121
                    mval = self.calc.per_second(mstr, int(values[mname]), ts)
122
                    result.add(plumd.Int(mstr, mval))
123
                else:
124
                    self.log.warn("netstat: unknown metric {0}".format(mname))
125
        return [result]
126