NetSnmp.check()   F
last analyzed

Complexity

Conditions 12

Size

Total Lines 66

Duplication

Lines 65
Ratio 98.48 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 65
loc 66
rs 2.6292
cc 12

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
"""SNMP metric reader for /proc on Linux."""
3
import time
4
from collections import deque
5
6
import plumd
7
from plumd.util import Differential
8
from plumd.util import Filter
9
10
__author__ = 'Kenny Freeman'
11
__email__ = '[email protected]'
12
__license__ = "ISCL"
13
__docformat__ = 'reStructuredText'
14
15
16
# todo: switch from list with pop(0) to deque
17
class NetSnmp(plumd.Reader):
18
    """Plugin to measure various kernel metrics from /proc."""
19
20
    defaults = {
21
        'poll.interval': 10,
22
        'proc_path': '/proc',
23
        'proc_netsnmp_gauges': {
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
        'proc_netsnmp_rates': {}
43
    }
44 View Code Duplication
45
    def __init__(self, log, config):
46
        """Plugin to measure various kernel metrics from /proc.
47
48
        :param log: A logger
49
        :type log: logging.RootLogger
50
        :param config: a plumd.config.Conf configuration helper instance.
51
        :type config: plumd.config.Conf
52
        """
53
        super(NetSnmp, self).__init__(log, config)
54
        self.config.defaults(NetSnmp.defaults)
55
        self.calc = Differential()
56
        self.proc_file = "{0}/net/snmp".format(config.get('proc_path'))
57
        self.filter = Filter()
58
        self.gauges = self.config.get('proc_netsnmp_gauges')
59
        self.rates = self.config.get('proc_netsnmp_rates')
60
61
    def poll(self):
62
        """Poll for kernel metrics under /proc.
63
64
        :rtype: ResultSet
65
        """
66
        return plumd.ResultSet(self.check())
67 View Code Duplication
68
    def check(self):
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
        result = plumd.Result("netsnmp")
80
81
        # read the proc file
82
        dat = []
83
        with open(self.proc_file, 'r') as pfd:
84
            dat = pfd.read().strip().split("\n")
85
86
        # timestamp for Differential calculations
87
        times = time.time()
88
89
        # split values into lists
90
        dlist = deque([entry.split() for entry in dat])
91
92
        # put lists into key: value dict
93
        metrics = {}
94
        while dlist:
95
            headers = dlist.popleft()
96
            values = dlist.popleft()
97
            # { 'IpExt': {'InNoRoutes': 0, ...} } - [:-1] on IpExt: removes :
98
            metrics[headers[0][:-1]] = dict(zip(headers, values))
99
100
        # record gauges
101
        for proto, mnames in self.gauges.items():
102
            if proto not in metrics:
103
                self.log.warn("netsnmp: unknown protocol: {0}".format(proto))
104
                del self.gauges[proto]
105
                continue
106
            values = metrics[proto]
107
            for mname in mnames:
108
                if mname in values:
109
                    mstr = "{0}.{1}".format(proto, mname)
110
                    result.add(plumd.Int(mstr, values[mname]))
111
                else:
112
                    self.log.warn("netstat: unknown metric {0}".format(mname))
113
                    self.gauges[proto].remove(mname)
114
                    continue
115
116
        # record rates
117
        for proto, mnames in self.rates.items():
118
            if proto not in metrics:
119
                self.log.warn("netsnmp: unknown protocol: {0}".format(proto))
120
                del self.gauges[proto]
121
                continue
122
            values = metrics[proto]
123
            for mname in mnames:
124
                if mname in values:
125
                    mstr = "{0}.{1}".format(proto, mname)
126
                    mval = self.calc.per_second(mstr, int(values[mname]), times)
127
                    result.add(plumd.Int(mstr, mval))
128
                else:
129
                    self.log.warn("netstat: unknown metric {0}".format(mname))
130
                    self.rates[proto].remove(mname)
131
                    continue
132
133
        return [result]
134