Actualizado el 22 de octubre de 2026.
Linux utiliza RAM como caché para acelerar el acceso a archivos. Alertar porque queda poca memoria completamente libre puede producir avisos aunque el sistema tenga margen para arrancar nuevas aplicaciones. La señal más útil para este chequeo es MemAvailable.
El kernel define MemAvailable como una estimación de la memoria disponible sin recurrir al intercambio. Tiene en cuenta memoria recuperable y reservas necesarias. Restarla del total no mide exactamente la suma de RAM de las aplicaciones; mide la parte que esa estimación considera no disponible.
Qué cambia respecto al script de 2010
La versión original adaptaba un plugin de Georg M. Sorst y buscaba en la salida de free la fila de buffers y caché. Ese formato no debe darse por estable. Además, el cálculo de swap dividía por cero en equipos sin swap y la rama de aviso usaba STATE_WARN, un nombre que podía no corresponder al de la biblioteca de plugins.
Este ejemplo lee directamente /proc/meminfo con Python 3. No interpreta la salida moderna ni antigua de free. Exige MemAvailable; si no existe, devuelve UNKNOWN en lugar de inventar un cálculo equivalente. Se ejecuta en el host Linux que quieres vigilar, sin privilegios de administrador.
Código del chequeo
Guárdalo como check_mem.py. Los porcentajes son de uso, no de memoria libre. -w y -c controlan RAM; -s y -S, swap. Cada aviso debe ser menor que su crítico, dentro de 0 a 100. Se alerta al superar el límite: exactamente 80 con aviso 80 no dispara WARNING.
#!/usr/bin/env python3
import argparse
from pathlib import Path
class PluginParser(argparse.ArgumentParser):
def error(self, message):
raise ValueError("argumentos invalidos; consulte --help")
def parse_meminfo(text):
required = {"MemTotal", "MemAvailable", "SwapTotal", "SwapFree"}
values = {}
for line in text.splitlines():
key, separator, value = line.partition(":")
if key not in required:
continue
fields = value.split()
if not separator or key in values or len(fields) != 2:
raise ValueError("meminfo mal formado")
if fields[1] != "kB" or not fields[0].isascii() or not fields[0].isdigit():
raise ValueError("unidad o valor de meminfo invalido")
values[key] = int(fields[0])
if values.keys() != required:
raise ValueError("faltan campos de meminfo; se requiere MemAvailable")
total, available = values["MemTotal"], values["MemAvailable"]
swap_total, swap_free = values["SwapTotal"], values["SwapFree"]
if total <= 0 or available > total or swap_free > swap_total:
raise ValueError("contadores de memoria incoherentes")
ram = (total - available) * 100 / total
swap = (swap_total - swap_free) * 100 / swap_total if swap_total else None
return ram, swap
def evaluate(ram, swap, warn, crit, swap_warn, swap_crit):
if not 0 <= warn < crit <= 100 or not 0 <= swap_warn < swap_crit <= 100:
raise ValueError("umbrales: 0 <= aviso < critico <= 100")
if ram > crit or (swap is not None and swap > swap_crit):
return 2
if ram > warn or (swap is not None and swap > swap_warn):
return 1
return 0
def main(argv=None):
parser = PluginParser(description="RAM no disponible y swap, porcentajes de uso")
parser.add_argument("-w", type=float, default=80)
parser.add_argument("-c", type=float, default=90)
parser.add_argument("-s", type=float, default=80)
parser.add_argument("-S", type=float, default=90)
try:
args = parser.parse_args(argv)
evaluate(0, None, args.w, args.c, args.s, args.S)
ram, swap = parse_meminfo(Path("/proc/meminfo").read_text(encoding="ascii"))
status = evaluate(ram, swap, args.w, args.c, args.s, args.S)
label = ("OK", "WARNING", "CRITICAL")[status]
swap_text = "sin swap" if swap is None else f"SWAP {swap:.2f}%"
perf = f"ram_used_pct={ram:.6f}%;{args.w};{args.c};0;100"
if swap is not None:
perf += f" swap_used_pct={swap:.6f}%;{args.s};{args.S};0;100"
print(f"{label}: RAM no disponible {ram:.2f}%; {swap_text} | {perf}")
return status
except SystemExit:
return 3
except (OSError, UnicodeError, ValueError, OverflowError):
print("UNKNOWN: revise argumentos y /proc/meminfo; se requiere MemAvailable")
return 3
if __name__ == "__main__":
raise SystemExit(main())
Salida y límites
python3 check_mem.py -w 80 -c 90 -s 80 -S 90
Devuelve una línea con el estado y datos de rendimiento. Los códigos son 0 para OK, 1 para WARNING, 2 para CRITICAL y 3 para UNKNOWN, conforme al contrato de plugins de monitorización. Los argumentos inválidos, la lectura fallida o los contadores incoherentes no se convierten en un OK silencioso.
Sin swap, muestra «sin swap» y evalúa únicamente RAM. No interpreta esa ausencia como fallo. Si tu política exige swap, necesitas un chequeo específico para esa política. Una swap ocupada tampoco demuestra por sí sola que haya actividad intensa de intercambio en ese instante.
Este chequeo mira la memoria del host que expone /proc/meminfo. No sirve para medir automáticamente el límite de un contenedor. Tampoco identifica qué proceso consume memoria ni detecta por sí solo presión de memoria u OOM.
Antes de activar notificaciones
Ejecuta el plugin con el usuario del agente de monitorización y comprueba su código de salida. Prueba estados normales, falta de MemAvailable, swap cero y límites inválidos en un entorno de pruebas. Después configura el comando con la ruta absoluta al intérprete y al archivo, sin aceptar fragmentos de shell desde parámetros externos.
Los valores 80 y 90 son puntos de partida del ejemplo. Ajusta los umbrales y la duración del aviso a la carga real, y observa varias muestras antes de convertir una fluctuación breve en una incidencia. El código no vacía cachés, mata procesos ni modifica la memoria del sistema.
Comentarios