Completed
Push — master ( bcff18...adb900 )
by Nicolas
01:15
created

glances.GlancesLogs.add()   F

Complexity

Conditions 11

Size

Total Lines 86

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 11
dl 0
loc 86
rs 3.1764

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 glances.GlancesLogs.add() 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
# This file is part of Glances.
4
#
5
# Copyright (C) 2015 Nicolargo <[email protected]>
6
#
7
# Glances is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU Lesser General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Glances is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU Lesser General Public License for more details.
16
#
17
# You should have received a copy of the GNU Lesser General Public License
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20
"""Manage logs."""
21
22
import time
23
from datetime import datetime
24
25
from glances.compat import range
26
from glances.processes import glances_processes
27
28
29
class GlancesLogs(object):
30
31
    """This class manages logs inside the Glances software.
32
33
    Logs is a list of list (stored in the self.logs_list var)
34
    item_state = "OK|CAREFUL|WARNING|CRITICAL"
35
    item_type = "CPU*|LOAD|MEM|MON"
36
    item_value = value
37
38
    Item is defined by:
39
      ["begin",
40
       "end",
41
       "WARNING|CRITICAL",
42
       "CPU|LOAD|MEM",
43
       MAX, AVG, MIN, SUM, COUNT,
44
       [top3 process list],
45
       "Processes description"]
46
    """
47
48
    def __init__(self):
49
        """Init the logs class."""
50
        # Maximum size of the logs list
51
        self.logs_max = 10
52
53
        # Init the logs list
54
        self.logs_list = []
55
56
    def get(self):
57
        """Return the raw logs list."""
58
        return self.logs_list
59
60
    def len(self):
61
        """Return the number of item in the logs list."""
62
        return self.logs_list.__len__()
63
64
    def __itemexist__(self, item_type):
65
        """Return the item position, if it exists.
66
67
        An item exist in the list if:
68
        * end is < 0
69
        * item_type is matching
70
        Return -1 if the item is not found.
71
        """
72
        for i in range(self.len()):
73
            if self.logs_list[i][1] < 0 and self.logs_list[i][3] == item_type:
74
                return i
75
        return -1
76
77
    def set_process_sort(self, item_type):
78
        """Define the process auto sort key from the alert type."""
79
        # Process sort depending on alert type
80
        if item_type.startswith("MEM"):
81
            # Sort TOP process by memory_percent
82
            process_auto_by = 'memory_percent'
83
        elif item_type.startswith("CPU_IOWAIT"):
84
            # Sort TOP process by io_counters (only for Linux OS)
85
            process_auto_by = 'io_counters'
86
        else:
87
            # Default sort is...
88
            process_auto_by = 'cpu_percent'
89
        glances_processes.auto_sort = True
90
        glances_processes.sort_key = process_auto_by
91
92
    def reset_process_sort(self):
93
        """Reset the process auto sort key."""
94
        # Default sort is...
95
        glances_processes.auto_sort = True
96
        glances_processes.sort_key = 'cpu_percent'
97
98
    def add(self, item_state, item_type, item_value,
99
            proc_list=None, proc_desc="", peak_time=6):
100
        """Add a new item to the logs list.
101
102
        If 'item' is a 'new one', add the new item at the beginning of
103
        the logs list.
104
        If 'item' is not a 'new one', update the existing item.
105
        If event < peak_time the the alert is not setoff.
106
        """
107
        proc_list = proc_list or []
108
109
        # Add or update the log
110
        item_index = self.__itemexist__(item_type)
111
        if item_index < 0:
112
            # Item did not exist, add if WARNING or CRITICAL
113
            if item_state == "WARNING" or item_state == "CRITICAL":
114
                # Define the automatic process sort key
115
                self.set_process_sort(item_type)
116
117
                # Create the new log item
118
                # Time is stored in Epoch format
119
                # Epoch -> DMYHMS = datetime.fromtimestamp(epoch)
120
                item = [
121
                    time.mktime(datetime.now().timetuple()),  # START DATE
122
                    -1,  # END DATE
123
                    item_state,  # STATE: WARNING|CRITICAL
124
                    item_type,  # TYPE: CPU, LOAD, MEM...
125
                    item_value,  # MAX
126
                    item_value,  # AVG
127
                    item_value,  # MIN
128
                    item_value,  # SUM
129
                    1,  # COUNT
130
                    # Process list is sorted automatically
131
                    # Overwrite the user choice
132
                    # topprocess = sorted(proc_list, key=lambda process: process[process_auto_by],
133
                    #                     reverse=True)
134
                    # topprocess[0:3],  # TOP 3 PROCESS LIST
135
                    [],  # TOP 3 PROCESS LIST
136
                    proc_desc]  # MONITORED PROCESSES DESC
137
138
                # Add the item to the list
139
                self.logs_list.insert(0, item)
140
                if self.len() > self.logs_max:
141
                    self.logs_list.pop()
142
        else:
143
            # Item exist, update
144
            if item_state == "OK" or item_state == "CAREFUL":
145
                # Reset the automatic process sort key
146
                self.reset_process_sort()
147
148
                endtime = time.mktime(datetime.now().timetuple())
149
                if endtime - self.logs_list[item_index][0] > peak_time:
150
                    # If event is > peak_time seconds
151
                    self.logs_list[item_index][1] = endtime
152
                else:
153
                    # If event <= peak_time seconds, ignore
154
                    self.logs_list.remove(self.logs_list[item_index])
155
            else:
156
                # Update the item
157
                # State
158
                if item_state == "CRITICAL":
159
                    self.logs_list[item_index][2] = item_state
160
                # Value
161
                if item_value > self.logs_list[item_index][4]:
162
                    # MAX
163
                    self.logs_list[item_index][4] = item_value
164
                elif item_value < self.logs_list[item_index][6]:
165
                    # MIN
166
                    self.logs_list[item_index][6] = item_value
167
                # AVG
168
                self.logs_list[item_index][7] += item_value
169
                self.logs_list[item_index][8] += 1
170
                self.logs_list[item_index][5] = (self.logs_list[item_index][7] /
171
                                                 self.logs_list[item_index][8])
172
                # TOP PROCESS LIST
173
                # # Process list is sorted automaticaly
174
                # # Overwrite the user choise
175
                # topprocess = sorted(proc_list, key=lambda process: process[process_auto_by],
176
                #                     reverse=True)
177
                # # TOP PROCESS LIST
178
                # self.logs_list[item_index][9] = topprocess[0:3]
179
                self.logs_list[item_index][9] = []
180
                # MONITORED PROCESSES DESC
181
                self.logs_list[item_index][10] = proc_desc
182
183
        return self.len()
184
185
    def clean(self, critical=False):
186
        """Clean the logs list by deleting finished items.
187
188
        By default, only delete WARNING message.
189
        If critical = True, also delete CRITICAL message.
190
        """
191
        # Create a new clean list
192
        clean_logs_list = []
193
        while self.len() > 0:
194
            item = self.logs_list.pop()
195
            if item[1] < 0 or (not critical and item[2].startswith("CRITICAL")):
196
                clean_logs_list.insert(0, item)
197
        # The list is now the clean one
198
        self.logs_list = clean_logs_list
199
        return self.len()
200
201
glances_logs = GlancesLogs()
202