LinuxMonitor 1.4.8__tar.gz → 1.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: LinuxMonitor
3
- Version: 1.4.8
3
+ Version: 1.5.0
4
4
  Summary: Get information and warning status of Linux server like service, port, ping, ssl certificate, disk/folder/cpu/ram/swap usage, ip connection, ... (Python and shell library, Linux ONLY)
5
5
  Home-page: https://github.com/QuentinCG/Linux-Monitor-Python-Library
6
6
  Author: Quentin Comte-Gaz
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: LinuxMonitor
3
- Version: 1.4.8
3
+ Version: 1.5.0
4
4
  Summary: Get information and warning status of Linux server like service, port, ping, ssl certificate, disk/folder/cpu/ram/swap usage, ip connection, ... (Python and shell library, Linux ONLY)
5
5
  Home-page: https://github.com/QuentinCG/Linux-Monitor-Python-Library
6
6
  Author: Quentin Comte-Gaz
@@ -71,6 +71,7 @@ def main() -> None:
71
71
  out_msg += msg
72
72
 
73
73
  out_msg += "\n"
74
+ out_msg += monitoring.check_load_average(display_only_if_critical=False) + "\n"
74
75
  out_msg += monitoring.check_cpu_usage(display_only_if_critical=False) + "\n"
75
76
  out_msg += monitoring.check_ram_usage(display_only_if_critical=False) + "\n"
76
77
  out_msg += monitoring.check_swap_usage(display_only_if_critical=False) + "\n"
@@ -33,7 +33,7 @@ __email__ = "quentin@comte-gaz.com"
33
33
  __license__ = "MIT License"
34
34
  __copyright__ = "Copyright Quentin Comte-Gaz (2024)"
35
35
  __python_version__ = "3.+"
36
- __version__ = "1.4.8 (2024/10/27)"
36
+ __version__ = "1.5.0 (2024/10/27)"
37
37
  __status__ = "Usable for any Linux project"
38
38
 
39
39
  import json
@@ -106,6 +106,14 @@ class LinuxMonitor:
106
106
  if not isinstance(basic_config, dict):
107
107
  raise ValueError("The basic configuration must be a dictionary")
108
108
 
109
+ if 'warning_load_average_percent' not in basic_config:
110
+ raise ValueError("The basic configuration must contain the 'warning_load_average_percent' key")
111
+ self.warning_load_average_percent: float = basic_config.get('warning_load_average_percent') # type: ignore
112
+
113
+ if 'critical_load_average_percent' not in basic_config:
114
+ raise ValueError("The basic configuration must contain the 'critical_load_average_percent' key")
115
+ self.critical_load_average_percent: float = basic_config.get('critical_load_average_percent') # type: ignore
116
+
109
117
  if 'warning_cpu_percent' not in basic_config:
110
118
  raise ValueError("The basic configuration must contain the 'warning_cpu_percent' key")
111
119
  self.warning_cpu_percent: float = basic_config.get('warning_cpu_percent') # type: ignore
@@ -587,15 +595,15 @@ class LinuxMonitor:
587
595
  cpu_cores: int = psutil.cpu_count(logical=False)
588
596
  cpu_name: str = self._get_cpu_name()
589
597
 
590
- if cpu_percent > self.critical_cpu_percent:
598
+ if cpu_percent >= self.critical_cpu_percent:
591
599
  out_msg = f"- 🚨 **Critical CPU usage**:\n- **{cpu_percent:.2f}%** used on {cpu_cores} core of {cpu_info:.2f}GHz ({cpu_name})\n⚠️ **Check what is using so much CPU power** ⚠️"
592
600
 
593
601
  # If there is a critical CPU usage, we also display the top 10 processes consuming the most CPU
594
- out_msg += "\n" + self.get_ordered_processes(get_non_consuming_processes: False, order_by_ram=False, max_processes=10)
602
+ out_msg += "\n" + self.get_ordered_processes(get_non_consuming_processes=False, order_by_ram=False, max_processes=10)
595
603
 
596
604
  logging.warning(msg=out_msg)
597
605
  elif not display_only_if_critical:
598
- if cpu_percent > self.warning_cpu_percent:
606
+ if cpu_percent >= self.warning_cpu_percent:
599
607
  icon = "⚠️"
600
608
  else:
601
609
  icon = "✅"
@@ -626,15 +634,15 @@ class LinuxMonitor:
626
634
  used_ram: float = ram.used / (2**30)
627
635
  free_ram: float = total_ram - used_ram
628
636
  percent_ram: float = ram.percent
629
- if percent_ram > self.critical_ram_percent:
637
+ if percent_ram >= self.critical_ram_percent:
630
638
  out_msg = f"- 🚨 **Critical RAM usage**:\n- Total: {total_ram:.2f}GB\n- Used: {used_ram:.2f}GB ({percent_ram:.2f}%)\n- Free: {free_ram:.2f}GB\n⚠️ **Check what is using so much RAM** ⚠️"
631
639
 
632
640
  # If there is a critical RAM usage, we also display the top 10 processes consuming the most RAM
633
- out_msg += "\n" + self.get_ordered_processes(get_non_consuming_processes: False, order_by_ram=True, max_processes=10)
641
+ out_msg += "\n" + self.get_ordered_processes(get_non_consuming_processes=False, order_by_ram=True, max_processes=10)
634
642
 
635
643
  logging.warning(msg=out_msg)
636
644
  elif not display_only_if_critical:
637
- if percent_ram > self.warning_ram_percent:
645
+ if percent_ram >= self.warning_ram_percent:
638
646
  icon = "⚠️"
639
647
  else:
640
648
  icon = "✅"
@@ -649,6 +657,45 @@ class LinuxMonitor:
649
657
 
650
658
  return out_msg
651
659
 
660
+ def check_load_average(self, display_only_if_critical: bool=False) -> str:
661
+ """
662
+ Check the load average.
663
+
664
+ :param display_only_if_critical: If True, the string result will only be returned if there is an error during execution.
665
+
666
+ :return: A string containing the result message.
667
+ """
668
+ out_msg: str = ""
669
+ try:
670
+ # Getting load average
671
+ load_avg = psutil.getloadavg()
672
+
673
+ # Getting an average of all 3 values
674
+ avg_load_avg: float = sum(load_avg) / len(load_avg)
675
+
676
+ if avg_load_avg >= self.critical_load_average_percent:
677
+ out_msg = f"- 🚨 **High load average**: **{avg_load_avg:.2f}%**\n⚠️ **Check what is causing the high load average** ⚠️"
678
+
679
+ # If there is a critical load average, we also display the top 10 processes consuming the most CPU
680
+ out_msg += "\n" + self.get_ordered_processes(get_non_consuming_processes=False, order_by_ram=False, max_processes=10)
681
+
682
+ logging.warning(msg=out_msg)
683
+ elif not display_only_if_critical:
684
+ if avg_load_avg >= self.warning_load_average_percent:
685
+ icon = "⚠️"
686
+ else:
687
+ icon = "✅"
688
+ out_msg = f"- {icon} **{avg_load_avg:.2f}%**"
689
+ logging.info(msg=out_msg)
690
+ except Exception as e:
691
+ out_msg = f"- ⚠️ **Error getting load average**:\n```sh\n{e}\n```"
692
+ logging.exception(msg=out_msg)
693
+
694
+ if out_msg != "":
695
+ out_msg = f"# 📈 Load Average 📈\n{out_msg}"
696
+
697
+ return out_msg
698
+
652
699
  def check_swap_usage(self, display_only_if_critical: bool=False) -> str:
653
700
  """
654
701
  Check the SWAP usage.
@@ -665,11 +712,11 @@ class LinuxMonitor:
665
712
  used_swap: float = swap.used / (2**30)
666
713
  free_swap: float = swap.free / (2**30)
667
714
  percent_swap: float = swap.percent
668
- if percent_swap > self.critical_swap_percent:
715
+ if percent_swap >= self.critical_swap_percent:
669
716
  out_msg = f"- 🚨 **Critical SWAP usage**\n- Total: {total_swap:.2f}GB\n- Used: {used_swap:.2f}GB ({percent_swap:.2f}%)\n- Free: {free_swap:.2f}GB\n⚠️ **Check what is using so much SWAP** ⚠️"
670
717
  logging.warning(msg=out_msg)
671
718
  elif not display_only_if_critical:
672
- if percent_swap > self.warning_swap_percent:
719
+ if percent_swap >= self.warning_swap_percent:
673
720
  icon = "⚠️"
674
721
  else:
675
722
  icon = "✅"
@@ -715,11 +762,11 @@ class LinuxMonitor:
715
762
  max_temp = max(temp.current for temp in cpu_temps) # type: ignore
716
763
 
717
764
  # Vérifier la température par rapport au seuil critique
718
- if max_temp > self.critical_temperature_celsius:
765
+ if max_temp >= self.critical_temperature_celsius:
719
766
  out_msg = f"- 🚨 **Critical CPU temperature**:\n- {max_temp:.2f}°C\n- Critical threshold: {self.critical_temperature_celsius}°C\n⚠️ **Check the CPU cooling system** ⚠️"
720
767
  logging.warning(msg=out_msg)
721
768
  elif not display_only_if_critical:
722
- if max_temp > self.warning_temperature_celsius:
769
+ if max_temp >= self.warning_temperature_celsius:
723
770
  icon = "⚠️"
724
771
  else:
725
772
  icon = "✅"
@@ -2048,6 +2095,7 @@ class LinuxMonitor:
2048
2095
 
2049
2096
  datetime_last_disk_usage_error_displayed: Optional[datetime] = None
2050
2097
  datetime_last_folder_usage_error_displayed: Optional[datetime] = None
2098
+ datetime_last_load_average_error_displayed: Optional[datetime] = None
2051
2099
  datetime_last_cpu_usage_error_displayed: Optional[datetime] = None
2052
2100
  datetime_last_ram_usage_error_displayed: Optional[datetime] = None
2053
2101
  datetime_last_swap_usage_error_displayed: Optional[datetime] = None
@@ -2071,6 +2119,28 @@ class LinuxMonitor:
2071
2119
  logging.info(msg="-----------------------------------------------")
2072
2120
  logging.info(msg="Checking services status and all disk usage, CPU, RAM, Swap, CPU temperature and ping of websites periodically...")
2073
2121
  try:
2122
+ # Load average
2123
+ if is_private:
2124
+ msg = self.check_load_average(display_only_if_critical=True)
2125
+ if msg != "":
2126
+ logging.warning(msg=msg)
2127
+ if datetime_last_load_average_error_displayed is None or ((datetime.now() - datetime_last_load_average_error_displayed).total_seconds() > self.max_duration_seconds_showing_same_error_again_in_scheduled_tasks):
2128
+ if out_msg != "":
2129
+ out_msg += "\n"
2130
+ out_msg += msg
2131
+ datetime_last_load_average_error_displayed = datetime.now()
2132
+ else:
2133
+ logging.warning(msg="Load average critical but already notified less than 12 hours ago, not notifying...")
2134
+ elif datetime_last_load_average_error_displayed is not None:
2135
+ msg = "✅ **Load average returned to normal state**"
2136
+ logging.info(msg=msg)
2137
+ if out_msg != "":
2138
+ out_msg += "\n"
2139
+ out_msg += msg
2140
+ datetime_last_load_average_error_displayed = None
2141
+ else:
2142
+ logging.info(msg="- ✅ Load average is OK.")
2143
+
2074
2144
  # CPU
2075
2145
  if is_private:
2076
2146
  msg = self.check_cpu_usage(display_only_if_critical=True)
@@ -6,7 +6,7 @@ with io.open(file='README.md', mode='r', encoding='utf-8') as readme_file:
6
6
 
7
7
  setup(
8
8
  name="LinuxMonitor",
9
- version="1.4.8",
9
+ version="1.5.0",
10
10
  description="Get information and warning status of Linux server like service, port, ping, ssl certificate, disk/folder/cpu/ram/swap usage, ip connection, ... (Python and shell library, Linux ONLY)",
11
11
  long_description=readme,
12
12
  long_description_content_type="text/markdown",
File without changes
File without changes
File without changes