You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

222 lines
7.7 KiB

4 years ago
  1. # -*- coding: utf-8 -*-
  2. #
  3. # This file is part of Glances.
  4. #
  5. # Copyright (C) 2018 Nicolargo <nicolas@nicolargo.com>
  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. """Manage logs."""
  20. import time
  21. from datetime import datetime
  22. from glances.compat import range
  23. from glances.processes import glances_processes, sort_stats
  24. class GlancesLogs(object):
  25. """This class manages logs inside the Glances software.
  26. Logs is a list of list (stored in the self.logs_list var)
  27. item_state = "OK|CAREFUL|WARNING|CRITICAL"
  28. item_type = "CPU*|LOAD|MEM|MON"
  29. item_value = value
  30. Item is defined by:
  31. ["begin",
  32. "end",
  33. "WARNING|CRITICAL",
  34. "CPU|LOAD|MEM",
  35. MAX, AVG, MIN, SUM, COUNT,
  36. [top3 process list],
  37. "Processes description",
  38. "top sort key"]
  39. """
  40. def __init__(self):
  41. """Init the logs class."""
  42. # Maximum size of the logs list
  43. self.logs_max = 10
  44. # Init the logs list
  45. self.logs_list = []
  46. def get(self):
  47. """Return the raw logs list."""
  48. return self.logs_list
  49. def len(self):
  50. """Return the number of item in the logs list."""
  51. return self.logs_list.__len__()
  52. def __itemexist__(self, item_type):
  53. """Return the item position, if it exists.
  54. An item exist in the list if:
  55. * end is < 0
  56. * item_type is matching
  57. Return -1 if the item is not found.
  58. """
  59. for i in range(self.len()):
  60. if self.logs_list[i][1] < 0 and self.logs_list[i][3] == item_type:
  61. return i
  62. return -1
  63. def get_process_sort_key(self, item_type):
  64. """Return the process sort key"""
  65. # Process sort depending on alert type
  66. if item_type.startswith("MEM"):
  67. # Sort TOP process by memory_percent
  68. ret = 'memory_percent'
  69. elif item_type.startswith("CPU_IOWAIT"):
  70. # Sort TOP process by io_counters (only for Linux OS)
  71. ret = 'io_counters'
  72. else:
  73. # Default sort is...
  74. ret = 'cpu_percent'
  75. return ret
  76. def set_process_sort(self, item_type):
  77. """Define the process auto sort key from the alert type."""
  78. glances_processes.auto_sort = True
  79. glances_processes.sort_key = self.get_process_sort_key(item_type)
  80. def reset_process_sort(self):
  81. """Reset the process auto sort key."""
  82. # Default sort is...
  83. glances_processes.auto_sort = True
  84. glances_processes.sort_key = 'cpu_percent'
  85. def add(self, item_state, item_type, item_value,
  86. proc_list=None, proc_desc="", peak_time=6):
  87. """Add a new item to the logs list.
  88. If 'item' is a 'new one', add the new item at the beginning of
  89. the logs list.
  90. If 'item' is not a 'new one', update the existing item.
  91. If event < peak_time the the alert is not setoff.
  92. """
  93. proc_list = proc_list or glances_processes.getlist()
  94. # Add or update the log
  95. item_index = self.__itemexist__(item_type)
  96. if item_index < 0:
  97. # Item did not exist, add if WARNING or CRITICAL
  98. self._create_item(item_state, item_type, item_value,
  99. proc_list, proc_desc, peak_time)
  100. else:
  101. # Item exist, update
  102. self._update_item(item_index, item_state, item_type, item_value,
  103. proc_list, proc_desc, peak_time)
  104. return self.len()
  105. def _create_item(self, item_state, item_type, item_value,
  106. proc_list, proc_desc, peak_time):
  107. """Create a new item in the log list"""
  108. if item_state == "WARNING" or item_state == "CRITICAL":
  109. # Define the automatic process sort key
  110. self.set_process_sort(item_type)
  111. # Create the new log item
  112. # Time is stored in Epoch format
  113. # Epoch -> DMYHMS = datetime.fromtimestamp(epoch)
  114. item = [
  115. time.mktime(datetime.now().timetuple()), # START DATE
  116. -1, # END DATE
  117. item_state, # STATE: WARNING|CRITICAL
  118. item_type, # TYPE: CPU, LOAD, MEM...
  119. item_value, # MAX
  120. item_value, # AVG
  121. item_value, # MIN
  122. item_value, # SUM
  123. 1, # COUNT
  124. [], # TOP 3 PROCESS LIST
  125. proc_desc, # MONITORED PROCESSES DESC
  126. glances_processes.sort_key] # TOP PROCESS SORTKEY
  127. # Add the item to the list
  128. self.logs_list.insert(0, item)
  129. if self.len() > self.logs_max:
  130. self.logs_list.pop()
  131. return True
  132. else:
  133. return False
  134. def _update_item(self, item_index, item_state, item_type, item_value,
  135. proc_list, proc_desc, peak_time):
  136. """Update a item in the log list"""
  137. if item_state == "OK" or item_state == "CAREFUL":
  138. # Reset the automatic process sort key
  139. self.reset_process_sort()
  140. endtime = time.mktime(datetime.now().timetuple())
  141. if endtime - self.logs_list[item_index][0] > peak_time:
  142. # If event is > peak_time seconds
  143. self.logs_list[item_index][1] = endtime
  144. else:
  145. # If event <= peak_time seconds, ignore
  146. self.logs_list.remove(self.logs_list[item_index])
  147. else:
  148. # Update the item
  149. # State
  150. if item_state == "CRITICAL":
  151. self.logs_list[item_index][2] = item_state
  152. # Value
  153. if item_value > self.logs_list[item_index][4]:
  154. # MAX
  155. self.logs_list[item_index][4] = item_value
  156. elif item_value < self.logs_list[item_index][6]:
  157. # MIN
  158. self.logs_list[item_index][6] = item_value
  159. # AVG (compute average value)
  160. self.logs_list[item_index][7] += item_value
  161. self.logs_list[item_index][8] += 1
  162. self.logs_list[item_index][5] = (self.logs_list[item_index][7] /
  163. self.logs_list[item_index][8])
  164. # TOP PROCESS LIST (only for CRITICAL ALERT)
  165. if item_state == "CRITICAL":
  166. # Sort the current process list to retreive the TOP 3 processes
  167. self.logs_list[item_index][9] = sort_stats(proc_list, glances_processes.sort_key)[0:3]
  168. self.logs_list[item_index][11] = glances_processes.sort_key
  169. # MONITORED PROCESSES DESC
  170. self.logs_list[item_index][10] = proc_desc
  171. return True
  172. def clean(self, critical=False):
  173. """Clean the logs list by deleting finished items.
  174. By default, only delete WARNING message.
  175. If critical = True, also delete CRITICAL message.
  176. """
  177. # Create a new clean list
  178. clean_logs_list = []
  179. while self.len() > 0:
  180. item = self.logs_list.pop()
  181. if item[1] < 0 or (not critical and item[2].startswith("CRITICAL")):
  182. clean_logs_list.insert(0, item)
  183. # The list is now the clean one
  184. self.logs_list = clean_logs_list
  185. return self.len()
  186. glances_logs = GlancesLogs()