Predecir el agotamiento del espacio en disco en qtile con un widget personalizado
Los desarrolladores de qtile pueden integrar el widget DiskSpaceAlert para prever el agotamiento del espacio en disco usando regresión lineal. Analiza tendencias en el espacio libre en sistemas de archivos reales —excluyendo los virtuales— y se activa cuando se cruza el umbral cero dentro de las próximas 24 horas. El widget hereda de InLoopPollText, actualizando cada 5 segundos mediante /proc/mounts y os.statvfs, utilizando un deque para mantener datos históricos.
El código funciona sin dependencias externas, ideal para entornos de escritorio sin Prometheus. El primer disparo ocurrió en /tmp (ext2 sobre zram, 16 GB): los registros en segundo plano llenaron la partición, provocando que una herramienta Bash fallara silenciosamente.
Filtrado de puntos de montaje
El widget ignora los sistemas de archivos virtuales y rutas del sistema, centrándose solo en discos físicos. Constantes definen exclusiones:
DISK_SPACE_SKIP_FS = {
'sysfs', 'proc', 'devtmpfs', 'devpts', 'tmpfs', 'securityfs',
'cgroup', 'cgroup2', 'pstore', 'debugfs', 'hugetlbfs', 'mqueue',
'configfs', 'fusectl', 'efivarfs', 'binfmt_misc', 'autofs',
'fuse.portal', 'nsfs', 'tracefs', 'bpf', 'ramfs', 'rpc_pipefs',
'nfsd', 'overlay', 'fuse.gvfsd-fuse',
}
DISK_SPACE_SKIP_PREFIXES = ('/sys/', '/proc/', '/dev/', '/run/')
La función get_mountpoints analiza /proc/mounts, omitiendo entradas por tipo de sistema de archivos o prefijo de ruta. Para tmpfs sobre zram, el filtro no se aplica, permitiendo detectar escenarios críticos.
def get_mountpoints(self):
mounts = []
try:
with open('/proc/mounts') as f:
for line in f:
parts = line.split()
if len(parts) < 3:
continue
mountpoint, fstype = parts[1], parts[2]
if fstype in DISK_SPACE_SKIP_FS:
continue
if any(mountpoint.startswith(p)
for p in DISK_SPACE_SKIP_PREFIXES):
continue
mounts.append(mountpoint)
except OSError:
pass
return mounts
Regresión lineal para predicción
La predicción utiliza mínimos cuadrados ordinarios (OLS) sin NumPy. Modela el espacio libre como y(t) = a·t + b, calculando el tiempo hasta que y=0. Fórmulas:
a = (n∑(t_i y_i) - ∑t_i ∑y_i) / (n∑t_i² - (∑t_i)²)b = (∑y_i - a ∑t_i) / n
Tiempo hasta agotamiento: -b / a menos el tiempo transcurrido. Si la pendiente ≥ 0 o seconds_left ≤ 0, devuelve None.
@staticmethod
def _predict_exhaustion(history, now):
n = len(history)
t = [h[0] - history[0][0] for h in history]
y = [h[1] for h in history]
sum_t = sum(t)
sum_y = sum(y)
sum_tt = sum(ti * ti for ti in t)
sum_ty = sum(ti * yi for ti, yi in zip(t, y))
denom = n * sum_tt - sum_t * sum_t
if denom == 0:
return None
slope = (n * sum_ty - sum_t * sum_y) / denom
intercept = (sum_y - slope * sum_t) / n
if slope >= 0:
return None
time_to_zero = -intercept / slope
elapsed = now - history[0][0]
seconds_left = time_to_zero - elapsed
if seconds_left > 0:
return seconds_left / 3600
return None
Una ventana deslizante de maxlen=120 (10 minutos a intervalos de 5 segundos) suaviza el ruido causado por archivos temporales.
Indicación de color y lógica de alerta
Dos niveles de alerta:
- Rojo (#FF0000): Consumo activo (espacio libre disminuyendo en los últimos 30 segundos) o menos del 10% libre.
- Naranja (#FF8800): Agotamiento previsto dentro de las próximas 24 horas, pero la tendencia se ha estabilizado.
El método _set_color actualiza self.foreground y self.layout.colour de forma eficiente, evitando redibujos innecesarios. Texto de etiqueta: DISCO /tmp: 8%libre, 2h restantes.
def _set_color(self, color):
self.foreground = color
if self.layout:
self.layout.colour = color
La historia se borra para sistemas de archivos desmontados.
— Editorial Team
Aún no hay comentarios.