3 Commits

Author SHA1 Message Date
b1ba8b9fab Use ping RTT for SNMP checker latency
Ping the host first to check availability and measure actual network
latency. Only proceed with SNMP query if the host is reachable.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 19:49:26 +01:00
624e3e7633 Fix SNMP latency to exclude Slim instance creation overhead
Move time measurement to only capture the actual SNMP GET request,
excluding the Slim() context manager initialization.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 19:44:14 +01:00
06e1d683b3 Fix ping latency to use actual RTT instead of subprocess time
Parse the real RTT from ping output instead of measuring subprocess
execution time, which included process startup overhead.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-26 19:38:37 +01:00
2 changed files with 56 additions and 17 deletions

View File

@@ -4,8 +4,8 @@ Checker Ping.
Vérifie la disponibilité d'un hôte via ICMP ping. Vérifie la disponibilité d'un hôte via ICMP ping.
""" """
import re
import subprocess import subprocess
import time
import platform import platform
from .base import BaseChecker, CheckResult from .base import BaseChecker, CheckResult
@@ -41,7 +41,6 @@ class PingChecker(BaseChecker):
else: else:
cmd = ["ping", "-c", str(count), "-W", str(timeout), host] cmd = ["ping", "-c", str(count), "-W", str(timeout), host]
start = time.time()
try: try:
result = subprocess.run( result = subprocess.run(
cmd, cmd,
@@ -49,9 +48,12 @@ class PingChecker(BaseChecker):
text=True, text=True,
timeout=timeout + 5 timeout=timeout + 5
) )
response_time = (time.time() - start) * 1000 # ms
if result.returncode == 0: if result.returncode == 0:
# Parse RTT from ping output (e.g., "time=0.32 ms" or "time=0.32ms")
match = re.search(r"time[=<]([\d.]+)\s*ms", result.stdout)
response_time = float(match.group(1)) if match else None
return CheckResult( return CheckResult(
success=True, success=True,
message="Host is reachable", message="Host is reachable",

View File

@@ -6,7 +6,9 @@ récupérer sa température.
""" """
import asyncio import asyncio
import time import platform
import re
import subprocess
from pysnmp.hlapi.v1arch.asyncio import ( from pysnmp.hlapi.v1arch.asyncio import (
Slim, Slim,
@@ -49,12 +51,43 @@ class SnmpChecker(BaseChecker):
""" """
return asyncio.run(self._async_check()) return asyncio.run(self._async_check())
def _ping(self, host: str, timeout: int) -> tuple[bool, float | None]:
"""
Exécute un ping vers l'hôte pour vérifier sa disponibilité.
Args:
host: Adresse IP ou nom d'hôte.
timeout: Délai d'attente en secondes.
Returns:
Tuple (succès, RTT en ms ou None).
"""
if platform.system().lower() == "windows":
cmd = ["ping", "-n", "1", "-w", str(timeout * 1000), host]
else:
cmd = ["ping", "-c", "1", "-W", str(timeout), host]
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=timeout + 5
)
if result.returncode == 0:
match = re.search(r"time[=<]([\d.]+)\s*ms", result.stdout)
return True, float(match.group(1)) if match else None
return False, None
except Exception:
return False, None
async def _async_check(self) -> CheckResult: async def _async_check(self) -> CheckResult:
""" """
Exécute la requête SNMP de manière asynchrone. Exécute la vérification SNMP de manière asynchrone.
Interroge l'OID principal et optionnellement l'OID de température Effectue d'abord un ping pour vérifier la disponibilité et mesurer
en une seule requête SNMP GET. la latence, puis interroge l'OID principal et optionnellement
l'OID de température via SNMP.
Returns: Returns:
CheckResult contenant le résultat et la température si configurée. CheckResult contenant le résultat et la température si configurée.
@@ -66,10 +99,18 @@ class SnmpChecker(BaseChecker):
temperature_oid = self.config.get("temperature_oid") temperature_oid = self.config.get("temperature_oid")
timeout_val = self.config.get("timeout", 5) timeout_val = self.config.get("timeout", 5)
start = time.time() # Ping d'abord pour vérifier la disponibilité et mesurer la latence
ping_success, response_time = self._ping(host, timeout_val)
if not ping_success:
return CheckResult(
success=False,
message="Host is unreachable",
response_time=None
)
# Requête SNMP
try: try:
with Slim() as slim: with Slim() as slim:
# Construit la liste des OIDs à interroger
oids = [ObjectType(ObjectIdentity(oid))] oids = [ObjectType(ObjectIdentity(oid))]
if temperature_oid: if temperature_oid:
oids.append(ObjectType(ObjectIdentity(temperature_oid))) oids.append(ObjectType(ObjectIdentity(temperature_oid)))
@@ -83,30 +124,26 @@ class SnmpChecker(BaseChecker):
retries=1 retries=1
) )
response_time = (time.time() - start) * 1000 # ms
if error_indication: if error_indication:
return CheckResult( return CheckResult(
success=False, success=False,
message=f"SNMP error: {error_indication}", message=f"SNMP error: {error_indication}",
response_time=None response_time=response_time
) )
elif error_status: elif error_status:
return CheckResult( return CheckResult(
success=False, success=False,
message=f"SNMP error: {error_status.prettyPrint()}", message=f"SNMP error: {error_status.prettyPrint()}",
response_time=None response_time=response_time
) )
else: else:
# Inclut uniquement l'OID principal dans les détails
details = {str(var_binds[0][0]): str(var_binds[0][1])} details = {str(var_binds[0][0]): str(var_binds[0][1])}
# Extrait la température si configurée (deuxième OID)
if temperature_oid and len(var_binds) >= 2: if temperature_oid and len(var_binds) >= 2:
try: try:
details["temperature"] = int(var_binds[1][1]) details["temperature"] = int(var_binds[1][1])
except (ValueError, TypeError): except (ValueError, TypeError):
pass # Ignore si la valeur n'est pas un entier pass
return CheckResult( return CheckResult(
success=True, success=True,
@@ -118,5 +155,5 @@ class SnmpChecker(BaseChecker):
return CheckResult( return CheckResult(
success=False, success=False,
message=f"SNMP error: {e}", message=f"SNMP error: {e}",
response_time=None response_time=response_time
) )