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

Netstat.check()   D

Complexity

Conditions 10

Size

Total Lines 59

Duplication

Lines 59
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
c 1
b 0
f 0
dl 59
loc 59
rs 4.8648

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 Netstat.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
class Netstat(plumd.plugins.Reader):
18
    """Plugin to measure various kernel metrics from /proc."""
19
    defaults = {
20
        'poll.interval': 10,
21
        'proc_path': '/proc',
22
        'proc_netstat_record': {
23
            'TcpExt': ["SyncookiesSent", "SyncookiesRecv",
24
                "SyncookiesFailed","OutOfWindowIcmps","TW","TWRecycled",
25
                "TWKilled","DelayedACKLost", "ListenOverflows",
26
                "ListenDrops","TCPLostRetransmit","TCPRenoFailures",
27
                "TCPSackFailures","TCPLossFailures","TCPFastRetrans",
28
                "TCPForwardRetrans","TCPSlowStartRetrans","TCPTimeouts",
29
                "TCPLossProbes","TCPLossProbeRecovery", "TCPAbortOnData",
30
                "TCPAbortOnClose", "TCPAbortOnMemory","TCPAbortOnTimeout",
31
                "TCPAbortOnLinger","TCPAbortFailed", "TCPMemoryPressures",
32
                "TCPBacklogDrop", "TCPMinTTLDrop","TCPTimeWaitOverflow",
33
                "TCPFastOpenActive","TCPFastOpenActiveFail",
34
                "TCPFastOpenPassive","TCPFastOpenPassiveFail",
35
                "TCPFastOpenListenOverflow","TCPSynRetrans"],
36
            'IpExt': ["InNoRoutes", "InTruncatedPkts", "InBcastPkts",
37
                "OutBcastPkts", "InOctets", "OutOctets", "InBcastOctets",
38
                "OutBcastOctets","InCsumErrors","InNoECTPkts","InECT1Pkts",
39
                "InECT0Pkts","InCEPkts"]
40
        }
41
    }
42
43
    def __init__(self, log, config):
44
        """Plugin to measure various kernel metrics from /proc.
45
46
        :param log: A logger
47
        :type log: logging.RootLogger
48
        :param config: a plumd.config.Conf configuration helper instance.
49
        :type config: plumd.config.Conf
50
        """
51
        super(Netstat, self).__init__(log, config)
52
        self.config.defaults(Netstat.defaults)
53
        self.calc = Differential()
54
        self.proc_file = "{0}/net/netstat".format(config.get('proc_path'))
55
56
57
    def poll(self):
58
        """Poll for kernel metrics under proc file net/netstat.
59
60
        :rtype: ResultSet
61
        """
62
        return plumd.ResultSet(self.check())
63
64
65 View Code Duplication
    def check(self):
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
66
        """Return detailed network statitistics proc file net/netstat.
67
68
        Note: add entries to the configuration value 'proc_netstat_record'
69
        to record them. See /proc/net/netstat for a list of available metrics.
70
71
        Note: ECT1Pkts and ECT0Pkts relate to ECT congestion notifications.
72
73
        :rtype: plumd.Result
74
        """
75
        # what metrics do we want to record?
76
        record = self.config.get('proc_netstat_record')
77
        result = plumd.Result("netstat")
78
79
        # read the proc file
80
        dat = None
81
        with open(self.proc_file, 'r') as f:
82
            try:
83
                dat = f.read().strip().split("\n")
84
            except Exception as e:
85
                self.log.error("failed to read {0}".format(self.proc_file))
86
                return result
87
88
        # timestamp for Differential calculations
89
        ts = time.time()
90
91
        # should always have a header row and value row, ie. divisible by 2
92
        if len(dat) % 2 != 0:
93
            self.log.error("netstat: cannot parse {0}".format(self.proc_file))
94
            return result
95
96
        # split values into lists
97
        dlist = deque()
98
        for entry in dat:
99
            dlist.append(entry.split())
100
101
        # put lists into key: value dict
102
        metrics = {}
103
        while dlist:
104
            headers = dlist.popleft()
105
            values = dlist.popleft()
106
            # { 'IpExt': {'InNoRoutes': 0, ...} } - [:-1] on IpExt: removes :
107
            metrics[headers[0][:-1]] = dict(zip(headers, values))
108
109
        # now, we have a list of items to record, just need to record them
110
        for ext, mnames in record.items():
111
            if ext not in metrics:
112
                self.log.warn("netstat: unknown extension: {0}".format(ext))
113
                continue
114
            values = metrics[ext]
115
            for mname in mnames:
116
                if mname in values:
117
                    mstr = "{0}.{1}".format(ext, mname)
118
                    mval = self.calc.per_second(mstr, int(values[mname]), ts)
119
                    result.add(plumd.Int(mstr, mval))
120
                else:
121
                    self.log.warn("netstat: unknown metric {0}".format(mname))
122
123
        return [result]
124