Volver al inicio

widget de qtile: predicción de espacio en disco

Widget DiskSpaceAlert para qtile predice agotamiento de espacio en disco por regresión lineal. Filtra FS virtuales, usa historial en deque, distingue amenazas activas y estabilizadoras. Código completo sin dependencias.

widget de qtile predice el fin de /tmp con antelación
Advertisement 728x90

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:

Google AdInline article slot
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.

Google AdInline article slot
@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.

Google AdInline article slot
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

Advertisement 728x90

Leer después