Ubuntu 24.04: logrotate no rota — el error de configuración que sigue afectando a la gente

¿Te fue útil?

Nada dice “viernes por la tarde” como un disco que se llena porque un archivo de registro decidió que en realidad es una base de datos. Revisas /etc/logrotate.d/, ves una sección para el servicio y, aun así, el archivo sigue creciendo. Sin rotaciones, sin compresión, sin piedad.

En Ubuntu 24.04, la razón más común por la que logrotate “no rota” no es systemd, ni un bug del kernel, ni rayos cósmicos. Es un único error de configuración: olvidaste especificar un disparador de rotación (daily/weekly/monthly/hourly o size) y asumiste que algún valor global por defecto te salvaría. No lo hará. Logrotate leerá tu sección, se encogerá de hombros educadamente y no hará nada—para siempre.

El único error: sin disparador, sin rotación

Logrotate no rota “porque existe un archivo” o “porque escribí un archivo de configuración”. Rota cuando una sección le indica cuándo rotar. Ese “cuándo” es un disparador de rotación:

  • daily, weekly, monthly, yearly, o (en muchas distribuciones) hourly
  • size (y complementos como minsize, maxsize)

Si tu archivo por servicio en /etc/logrotate.d/ no especifica un disparador, estás confiando en la herencia. Y aquí es donde la gente se equivoca: los valores globales de Ubuntu pueden no proporcionar un calendario de modo que se aplique a tu sección (o el archivo no se está leyendo, o lo estás sobrescribiendo sin querer). Resultado neto: logrotate se ejecuta, no ve razón para rotar, no actualiza nada y sale con código 0 como si te hubiera hecho un favor.

Cómo se ve la configuración rota

Esta es la sección clásica que “parece bien en una revisión de código, falla en producción”. Observa lo que falta:

cr0x@server:~$ sudo sed -n '1,120p' /etc/logrotate.d/myapp
/var/log/myapp/myapp.log {
  rotate 7
  compress
  missingok
  notifempty
  create 0640 myapp adm
  postrotate
    systemctl kill -s HUP myapp.service
  endscript
}

La configuración tiene rotate 7, que solo indica “conservar siete logs antiguos” si ocurre la rotación. No dice cuándo rotar. Si no especificas daily (o similar) o size, logrotate no puede tomar una decisión de rotación.

Cómo se ve la configuración corregida

Añade un disparador explícito. Elige uno. No hagas que el lector adivine.

cr0x@server:~$ sudo sed -n '1,120p' /etc/logrotate.d/myapp
/var/log/myapp/myapp.log {
  daily
  rotate 7
  compress
  missingok
  notifempty
  create 0640 myapp adm
  postrotate
    systemctl kill -s HUP myapp.service
  endscript
}

Si prefieres rotación basada en tamaño (a menudo mejor para aplicaciones ruidosas):

cr0x@server:~$ sudo sed -n '1,120p' /etc/logrotate.d/myapp
/var/log/myapp/myapp.log {
  size 200M
  rotate 10
  compress
  delaycompress
  missingok
  notifempty
  create 0640 myapp adm
}

Haz el disparador explícito incluso si te parece “obvio”. La producción es donde las suposiciones obvias van a ser auditadas.

Guía de diagnóstico rápido (primero/segundo/tercero)

Cuando logrotate “no rota”, quieres localizar el cuello de botella rápido: ¿es programación, análisis, elegibilidad, permisos o falla en postrotate?

Primero: confirma que logrotate realmente se invoca

  • Comprueba el estado del temporizador/servicio systemd y la última hora de ejecución.
  • Revisa los logs del journal para ejecuciones y errores de logrotate.

Segundo: ejecuta logrotate en modo debug para la configuración específica

  • Usa -d (debug) y -v (verbose) para ver el árbol de decisiones.
  • Busca líneas como “log does not need rotating” y la razón detrás.

Tercero: revisa el archivo de estado y la lógica del disparador

  • Inspecciona /var/lib/logrotate/status (o la variante de la distro) para ver qué cree logrotate que rotó por última vez.
  • Valida que tu sección contenga un disparador (daily/weekly/size, etc.).
  • Confirma que las rutas de archivos coincidan con la realidad (incluyendo comodines) y que los permisos permitan la rotación.

Si haces solo una cosa: ejecuta logrotate con -d -v y léelo como un registrador de vuelo. Normalmente es vergonzosamente honesto.

Cómo decide realmente logrotate (realidad en Ubuntu 24.04)

La tarea de logrotate es simple: para cada archivo de log, decidir si es necesaria la rotación; si sí, renombrar/truncar/copiar, opcionalmente comprimir, y ejecutar scripts. El diablo está en el archivo de estado y los disparadores.

Programación en Ubuntu 24.04: timers systemd, no cron clásico

En Ubuntu moderno, logrotate normalmente se lanza mediante un temporizador de systemd (no con un job cron.daily clásico). Eso cambia dónde mirar cuando depuras “nunca se ejecuta”. También cambia cómo se comportan las ejecuciones “perdidas”: los timers pueden recuperar ejecuciones dependiendo de la configuración.

El archivo de estado es la memoria que logrotate usa

Logrotate no es un daemon en tiempo real. Se ejecuta, toma decisiones y sale. Para evitar rotar todo cada vez, almacena marcas de tiempo de la última rotación en un archivo de estado (comúnmente /var/lib/logrotate/status). Si ese archivo dice que un log se rotó “hoy”, una sección daily no rotará otra vez solo porque estés ansioso.

Los disparadores no son opcionales

Logrotate no infiere un calendario de rotación a partir de rotate N, compress o create. Esas son acciones. Los disparadores son independientes. La ausencia de disparador es el modo silencioso de fallo porque no es “sintaxis inválida”. Es simplemente “ninguna condición satisfecha”.

Parafraseando a Richard Cook: “El éxito oculta los bordes afilados del sistema; el fallo revela cómo se hace realmente el trabajo”. Eso es depurar logrotate en una frase.

Broma #1: Logrotate es como la rotación de guardias: si nunca defines el horario, alguien seguirá sufriendo—solo que no será el software.

Tareas prácticas: comandos, salidas, decisiones (12+)

A continuación hay tareas concretas que realmente uso en respuesta a incidentes. Cada una incluye: el comando, qué significa la salida y la decisión que tomas a partir de ella.

Tarea 1: Confirma que el timer existe y está habilitado

cr0x@server:~$ systemctl status logrotate.timer
● logrotate.timer - Daily rotation of log files
     Loaded: loaded (/usr/lib/systemd/system/logrotate.timer; enabled; preset: enabled)
     Active: active (waiting) since Sat 2025-12-28 07:10:22 UTC; 2h 14min ago
    Trigger: Sun 2025-12-29 00:00:00 UTC; 14h left
   Triggers: ● logrotate.service

Significado: Si está habilitado y “Active (waiting)”, la programación probablemente esté bien.

Decisión: Si está deshabilitado/falta, arregla la programación primero. Si está habilitado, pasa a comprobar la ejecución del servicio y el journal.

Tarea 2: Confirma la última ejecución del servicio y el código de salida

cr0x@server:~$ systemctl status logrotate.service
● logrotate.service - Rotate log files
     Loaded: loaded (/usr/lib/systemd/system/logrotate.service; static)
     Active: inactive (dead) since Sat 2025-12-28 00:00:04 UTC; 9h ago
    Process: 1042 ExecStart=/usr/sbin/logrotate /etc/logrotate.conf (code=exited, status=0/SUCCESS)

Significado: El estado 0 significa que logrotate no se bloqueó; aún puede no haber rotado nada.

Decisión: Si el estado es distinto de cero, inspecciona los logs; si es éxito, procede al modo debug para entender por qué se saltó la rotación.

Tarea 3: Inspecciona el journal en busca de mensajes de logrotate

cr0x@server:~$ journalctl -u logrotate.service -n 50 --no-pager
Dec 28 00:00:01 server systemd[1]: Starting logrotate.service - Rotate log files...
Dec 28 00:00:04 server systemd[1]: logrotate.service: Deactivated successfully.
Dec 28 00:00:04 server systemd[1]: Finished logrotate.service - Rotate log files.

Significado: No hay errores aquí, pero tampoco detalle. Eso es normal; logrotate solo escribe a stdout cuando se usa verbose/debug.

Decisión: Ejecuta debug manual a continuación.

Tarea 4: Simulación (dry-run) de logrotate con verbose + debug

cr0x@server:~$ sudo logrotate -d -v /etc/logrotate.conf
reading config file /etc/logrotate.conf
including /etc/logrotate.d
reading config file /etc/logrotate.d/myapp
Handling 1 logs
rotating pattern: /var/log/myapp/myapp.log  after 1 days (7 rotations)
empty log files are not rotated, old logs are removed
considering log /var/log/myapp/myapp.log
  log does not need rotating (log has been already rotated)

Significado: Esto te dice lo que logrotate cree que es el disparador (“after 1 days”) y por qué se salta la rotación (“already rotated”).

Decisión: Si la línea del disparador falta o es extraña, inspecciona la sección. Si dice “already rotated”, revisa el archivo de estado.

Tarea 5: Ejecuta debug para un archivo de configuración único (alcance reducido)

cr0x@server:~$ sudo logrotate -d -v /etc/logrotate.d/myapp
reading config file /etc/logrotate.d/myapp
error: /etc/logrotate.d/myapp:2 unknown option 'rotato'

Significado: El debug por archivo detecta rápidamente errores tipográficos y problemas de parsing.

Decisión: Corrige errores de sintaxis antes de perseguir comportamientos en tiempo de ejecución.

Tarea 6: Valida que la sección incluya un disparador (la comprobación del “único error”)

cr0x@server:~$ sudo egrep -n 'daily|weekly|monthly|yearly|hourly|size|minsize|maxsize' /etc/logrotate.d/myapp || echo "NO TRIGGER FOUND"
NO TRIGGER FOUND

Significado: No se encuentran palabras clave de disparador. Este es el clásico error de “rota pero nunca rota”.

Decisión: Añade daily o size explícitamente y vuelve a ejecutar el debug.

Tarea 7: Inspecciona la entrada del archivo de estado para tu log

cr0x@server:~$ sudo grep -F '/var/log/myapp/myapp.log' /var/lib/logrotate/status
"/var/log/myapp/myapp.log" 2025-12-28-0:0:0

Significado: Logrotate cree que rotó a medianoche hoy. Si tu expectativa es “debería rotar ahora”, tu expectativa es el error.

Decisión: Si la marca temporal parece errónea, investiga cambios de hora, corrupción del estado o rutas duplicadas. No borres el archivo de estado a la ligera en producción.

Tarea 8: Confirma el tamaño real del archivo y la hora de modificación

cr0x@server:~$ ls -lh --time-style=long-iso /var/log/myapp/myapp.log
-rw-r----- 1 myapp adm 12G 2025-12-28 09:19 /var/log/myapp/myapp.log

Significado: El archivo es enorme y sigue siendo escrito. Si usas rotación basada en tiempo únicamente, podrías estar “correcto” pero operativamente condenado.

Decisión: Considera size o maxsize además de disparadores temporales.

Tarea 9: Comprueba quién es el propietario del log y los permisos del directorio

cr0x@server:~$ namei -l /var/log/myapp/myapp.log
f: /var/log/myapp/myapp.log
drwxr-xr-x root root /
drwxr-xr-x root root var
drwxrwxr-x root syslog log
drwxr-x--- myapp adm myapp
-rw-r----- myapp adm myapp.log

Significado: El directorio de logs no es accesible a “otros”; logrotate corre como root (normalmente), así que eso está bien. Pero si configuraste su incorrectamente, los permisos pueden bloquear la rotación.

Decisión: Si los permisos no permiten renombrar/crear, arregla la propiedad/modo o usa la directiva correcta su user group.

Tarea 10: Detecta fallos en el script postrotate (la razón oculta de que nada cambie)

cr0x@server:~$ sudo logrotate -v /etc/logrotate.d/myapp
reading config file /etc/logrotate.d/myapp
rotating pattern: /var/log/myapp/myapp.log  after 1 days (7 rotations)
considering log /var/log/myapp/myapp.log
  log needs rotating
rotating log /var/log/myapp/myapp.log, log->rotateCount is 7
renaming /var/log/myapp/myapp.log to /var/log/myapp/myapp.log.1
creating new /var/log/myapp/myapp.log mode = 0640 uid = 123 gid = 4
running postrotate script
error: error running shared postrotate script for '/var/log/myapp/myapp.log '

Significado: La rotación puede haber ocurrido, pero el paso de señal/reload falló. Algunas aplicaciones siguen escribiendo en el inode antiguo; otras necesitan HUP para reabrir logs.

Decisión: Arregla postrotate; de lo contrario “rotarás” y seguirás llenando disco porque el proceso escribe en un descriptor de archivo no enlazado.

Tarea 11: Comprueba la temida situación “eliminado pero aún abierto”

cr0x@server:~$ sudo lsof +L1 | head
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NLINK     NODE NAME
myapp    2210 myapp   7w   REG  252,0 12884901888     0  393502 /var/log/myapp/myapp.log (deleted)

Significado: El archivo está eliminado/rotado, pero el proceso sigue escribiendo en el descriptor antiguo. El uso de disco no disminuirá.

Decisión: Arregla tu estrategia de reapertura: HUP, reload, o usa copytruncate como último recurso (con los ojos abiertos).

Tarea 12: Verifica que el timer realmente se disparó cuando crees que lo hizo

cr0x@server:~$ systemctl list-timers --all | grep -F logrotate
Sun 2025-12-29 00:00:00 UTC 14h left Sat 2025-12-28 00:00:01 UTC 9h ago logrotate.timer logrotate.service

Significado: La última ejecución fue a medianoche; la siguiente a medianoche. Si tu log explotó a las 09:00, la rotación diaria basada en tiempo no te salvará.

Decisión: Añade umbrales de tamaño o aumenta la frecuencia de ejecución (con cuidado).

Tarea 13: Fuerza una rotación puntual (con seguridad) para validar la mecánica

cr0x@server:~$ sudo logrotate -f -v /etc/logrotate.d/myapp
reading config file /etc/logrotate.d/myapp
rotating pattern: /var/log/myapp/myapp.log  forced from command line (7 rotations)
considering log /var/log/myapp/myapp.log
  log needs rotating
renaming /var/log/myapp/myapp.log to /var/log/myapp/myapp.log.1
creating new /var/log/myapp/myapp.log mode = 0640 uid = 123 gid = 4

Significado: La mecánica funciona: renombrar/crear/permisos están bien.

Decisión: Si la rotación forzada funciona pero la programada no, es un problema de disparador/estado/programación, no de permisos.

Tarea 14: Comprueba el orden de los includes y si tu archivo se lee

cr0x@server:~$ sudo grep -nE '^(include|#include)|/etc/logrotate\.d' /etc/logrotate.conf
12:include /etc/logrotate.d

Significado: Si falta el include, nada en /etc/logrotate.d importa.

Decisión: Restaura la línea de include si alguien “simplificó” la configuración global.

Tarea 15: Prueba parsing de la configuración sin ejecutar rotaciones (comprobación de cordura)

cr0x@server:~$ sudo logrotate -d /etc/logrotate.conf | tail -n 20
considering log /var/log/myapp/myapp.log
  Now: 2025-12-28 09:24
  Last rotated at 2025-12-28 00:00
  log does not need rotating

Significado: El modo debug muestra “Now” y “Last rotated”. Si esos son absurdos, sigue la pista de tiempo/estado.

Decisión: Si “Last rotated” está en el futuro, probablemente tengas desincronización horaria, una snapshot restaurada de VM o un archivo de estado copiado.

Errores comunes: síntoma → causa raíz → solución

1) “Puse rotate 30 pero nunca rota”

Síntoma: El archivo crece sin fin; logrotate informa éxito; no existen archivos rotados.

Causa raíz: Falta directiva de disparador (daily/weekly/size).

Solución: Añade un disparador explícito. Prefiere size para logs de alto volumen; mantén rotación por tiempo para alinear retención.

2) “Logrotate se ejecuta, pero dice ‘log does not need rotating’ mientras el archivo es enorme”

Síntoma: Un archivo de 20G; debug dice que no rota.

Causa raíz: Configuraste solo daily y ya rotó hoy; o el archivo de estado dice que lo hizo.

Solución: Añade maxsize o size. O rota con más frecuencia. No pelees con el archivo de estado; diseña alrededor de él.

3) “Existen archivos rotados, pero el uso de disco nunca baja”

Síntoma: Ves myapp.log.1, pero df sigue mostrando alto uso.

Causa raíz: El proceso aún mantiene abierto el inode antiguo (eliminado); los logs van a un descriptor (deleted).

Solución: Asegura que el proceso reabra logs (HUP/reload) o usa copytruncate si la app no puede reabrir (aceptando pérdida/riesgo de carrera).

4) “logrotate -f manual funciona, la rotación programada no”

Síntoma: Rotación forzada funciona; el temporizador diario no hace nada.

Causa raíz: Programación no se dispara, timer deshabilitado, include faltante o el estado dice que ya rotó.

Solución: Comprueba systemctl list-timers, verifica que /etc/logrotate.conf incluya /etc/logrotate.d, inspecciona /var/lib/logrotate/status.

5) “Errores de rotación: permiso denegado”

Síntoma: Debug/verbose muestra fallos al renombrar/crear.

Causa raíz: Propietario/mode incorrecto; directorio de logs no escribible; uso incorrecto de su; o logs en un montaje con restricciones.

Solución: Arregla permisos del sistema de archivos. Si usas su, asegúrate de que user/group coincidan con el propietario del log y que los permisos del directorio permitan la rotación.

6) “Rota, pero la app deja de escribir en el log”

Síntoma: Después de la rotación, el archivo de log queda vacío y la app sigue en ejecución.

Causa raíz: La app sigue escribiendo al fd antiguo; el nuevo archivo existe pero no se usa; postrotate no señala correctamente.

Solución: Usa la acción postrotate correcta: HUP, reload o comando específico del servicio. Valida con lsof.

7) “Usé comodines y no pasa nada”

Síntoma: La sección referencia /var/log/myapp/*.log; no ocurren rotaciones.

Causa raíz: El patrón no coincide con nada; los permisos impiden la expansión del glob en el directorio; o los logs están en otra ruta distinta a la esperada.

Solución: Confirma coincidencias con ls. Usa rutas explícitas para logs críticos.

8) “Tras restaurar una imagen, logrotate no rota durante días”

Síntoma: El debug dice que la última rotación fue en el futuro.

Causa raíz: Archivo de estado copiado desde otra máquina/tiempo; snapshot de VM restaurada; cambios de reloj.

Solución: Corrige la hora primero. Luego ajusta la entrada de estado con cuidado (edita solo la línea afectada), o fuerza una rotación con -f y confirma que el estado se actualiza.

Tres microhistorias corporativas desde las trincheras

Incidente #1: la suposición equivocada (“rotate 14 significa cada 14 días, ¿no?”)

Una empresa SaaS mediana tenía un servicio interno que emitía logs JSON. Funcionó durante meses porque nadie miraba la utilización del filesystem root del nodo a menos que algo saltara. El servicio añadió una característica que duplicó el volumen de logs—nada dramático, solo más campos de contexto.

Dos semanas después, un ingeniero en on-call vio que el uso de disco en un nodo de producción estaba al 97%. Encontraron /var/log/internal/worker.log con decenas de gigabytes. Había una sección de logrotate con rotate 14, compress, create y notifempty. Parecía “configurado”. Todos asumieron que “rotate 14” significaba “rotar cada 14 días”. No es así.

El temporizador se estaba ejecutando. Logrotate salió con 0. Sin rotaciones. La configuración no tenía daily, ni weekly, ni size. Era una política sin disparador—como escribir “mantener 14 copias” sin ejecutar nunca el backup.

Añadieron daily y maxsize 500M, forzaron una rotación para recuperar espacio y luego ajustaron los umbrales de monitorización para alertar sobre crecimiento de logs antes del pánico del filesystem.

El postmortem fue cortés pero claro: “Asumimos que logrotate tenía un calendario por defecto. No probamos el comportamiento de rotación en staging con volúmenes realistas.” Esa historia se repite en todas partes.

Incidente #2: la optimización que salió mal (copytruncate por todas partes)

Una empresa regulada tenía una app Java legacy que no reabría logs bien con HUP. Alguien “resolvió” esto hace años con copytruncate. Funcionó lo suficiente como para convertirse en el patrón por defecto para nuevos servicios—copytruncate para todo, siempre.

Después movieron cargas a NVMe más rápidas y aumentaron el throughput. Su servicio más ocupado empezó a escribir varios gigabytes por hora. La rotación tardaba tanto que la ventana de truncado importaba, y comenzaron a perder líneas de log. No “quizás”; demostrable. El rastro de auditoría tenía huecos justo en los límites de rotación.

Peor aún, la compresión se ejecutaba inmediatamente, golpeando la CPU en horas pico. La “optimización” creó un acantilado de rendimiento: durante la rotación, los picos de CPU aumentaban la latencia de las peticiones, lo que causaba reintentos, que generaban más logs, que provocaban rotaciones más grandes. Un bonito bucle de retroalimentación auto-infligido.

Revirtieron: pasaron a rotación basada en rename (sin copytruncate) y arreglaron la app para que reabra logs correctamente ante una señal. También añadieron delaycompress para desplazar la compresión fuera del momento crítico. No fue trabajo glamuroso. Fue trabajo correcto.

Broma #2: “Usamos copytruncate para evitar cambiar la app” es el equivalente en logging a arreglar una fuga comprando una fregona más grande.

Incidente #3: la práctica aburrida que salvó el día (disparadores explícitos + pruebas forzadas)

Un pequeño equipo de plataforma gestionaba decenas de servicios internos, mayoritariamente Go y Python, en Ubuntu. Tenían un hábito que parecía excesivamente pedante: cada sección de logrotate tenía un disparador explícito y un comentario que explicaba por qué. Nada de herencia. Ninguna dependencia de /etc/logrotate.conf. Cada sección: daily o size (a menudo ambos vía maxsize), siempre intencional.

También tenían un elemento en la checklist de despliegue: después de desplegar un nuevo servicio, ejecutar logrotate -d -v contra su sección y pegar el fragmento de salida en el registro de cambios. Eso parecía burocracia hasta que un cambio en la imagen base alteró algunos valores globales y unos servicios cayeron en nodos nuevos.

Los servicios con disparadores explícitos rotaron con normalidad. Los que confiaban en la herencia (de configuraciones de otros equipos) se comportaron de forma extraña: algunos rotaron semanalmente cuando la gente esperaba diario; otros solo rotaron cuando alcanzaron un umbral por tamaño que nadie recordaba haber establecido. El equipo de plataforma no tuvo incidente. Tuvieron un martes molesto.

La diferencia no era mágica. Era la práctica aburrida de dejar explícito “cuándo rotar” y luego probar el comportamiento una vez, de la misma forma que probarías una regla de firewall o una copia de seguridad. Eso es profesionalismo en ops: prevenir sorpresas, no reaccionar heroicamente a ellas.

Hechos interesantes y contexto (por qué esto sigue ocurriendo)

  1. Logrotate es anterior a systemd por décadas. Creció en un mundo impulsado por cron, y el cambio a timers de systemd cambió dónde mira la gente cuando falla.
  2. El archivo de estado es el núcleo de la “memoria” de logrotate. Sin él, la rotación basada en tiempo rotaría constantemente o requeriría heurísticas con metadatos del filesystem.
  3. rotate N es retención, no programación. Este es el error conceptual más común—porque la palabra “rotate” hace demasiado trabajo.
  4. Muchas distros distribuyen una configuración global que parece establecer valores por defecto. La gente asume que esos valores incluyen un disparador. A veces lo hacen; a veces tu sección los sobrescribe; a veces tu archivo ni siquiera está incluido.
  5. Journald redujo la dependencia de logs en archivos para algunos servicios. Pero muchas apps siguen escribiendo a ficheros (compatibilidad, cumplimiento, o porque la imagen del contenedor viene de 2016 y nadie quiere tocarla).
  6. Copytruncate se popularizó porque “funciona” con apps tercas. También introduce carreras y pérdida potencial bajo carga porque la escritura puede ocurrir mientras se copia.
  7. La compresión solía ser lo bastante costosa como para programarla con cuidado. En CPUs modernas es más barato, pero aún importa cuando comprimes logs de varios GB en horas pico.
  8. Renombrar logs es atómico; truncar no lo es. El enfoque basado en rename se alinea con cómo se comportan los descriptores de archivos en Unix y suele ser más seguro cuando las apps reabren logs correctamente.
  9. Las configuraciones de logrotate son engañosamente permisivas. Muchas malas configuraciones no son errores de sintaxis; son errores lógicos que resultan en “no hacer nada con éxito”.

Listas de verificación / plan paso a paso

Paso a paso: poner la rotación en funcionamiento para un log problemático

  1. Confirma que existe la programación.

    cr0x@server:~$ systemctl status logrotate.timer
    ● logrotate.timer - Daily rotation of log files
         Loaded: loaded (/usr/lib/systemd/system/logrotate.timer; enabled; preset: enabled)
         Active: active (waiting) since Sat 2025-12-28 07:10:22 UTC; 2h 14min ago
        Trigger: Sun 2025-12-29 00:00:00 UTC; 14h left
       Triggers: ● logrotate.service

    Decisión: Si está deshabilitado, habilítalo. Si está habilitado, continúa.

  2. Demuestra que tu configuración está incluida.

    cr0x@server:~$ sudo grep -n 'include /etc/logrotate.d' /etc/logrotate.conf
    12:include /etc/logrotate.d

    Decisión: Si falta, restaura el include y vuelve a probar.

  3. Ejecuta debug para esa sección.

    cr0x@server:~$ sudo logrotate -d -v /etc/logrotate.d/myapp | sed -n '1,120p'
    reading config file /etc/logrotate.d/myapp
    Handling 1 logs
    considering log /var/log/myapp/myapp.log
      log does not need rotating

    Decisión: Si no menciona un calendario/tamaño, probablemente no tienes disparador.

  4. Añade un disparador explícito.

    Elige uno: basado en tiempo (daily) o en volumen (size / maxsize). Para logs de alto volumen, la rotación por tamaño suele ser la elección madura.

  5. Fuerza una rotación una vez para validar la mecánica.

    cr0x@server:~$ sudo logrotate -f -v /etc/logrotate.d/myapp | tail -n 30
    considering log /var/log/myapp/myapp.log
      log needs rotating
    renaming /var/log/myapp/myapp.log to /var/log/myapp/myapp.log.1
    creating new /var/log/myapp/myapp.log mode = 0640 uid = 123 gid = 4

    Decisión: Si la rotación forzada falla, arregla permisos/rutas antes de culpar a la programación.

  6. Asegura que la app escribe en el nuevo log.

    cr0x@server:~$ sudo lsof /var/log/myapp/myapp.log | head
    COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
    myapp   2210 myapp   7w   REG  252,0   123456  401 /var/log/myapp/myapp.log

    Decisión: Si sigue escribiendo en un inode eliminado, arregla postrotate o el comportamiento de reapertura de la app.

Lista operativa: lo que espero en una sección de producción

  • Un disparador explícito: daily o size/maxsize.
  • Retención explícita: rotate N más compress y normalmente delaycompress.
  • Creación correcta: create MODE USER GROUP o confiar en la app para crearla de forma segura (elige con intención).
  • Estrategia segura de reapertura: señal/reload en postrotate, validada con lsof.
  • No confiar en la herencia a menos que la hayas probado y puedas explicarla a alguien medio dormido.
  • Guardarraíles de tamaño para servicios de alto volumen: maxsize evita que la rotación diaria sea demasiado tardía.

FAQ

1) ¿Por qué logrotate sale con éxito incluso cuando no rota nada?

Porque “no hay logs que necesiten rotarse” es un resultado válido. Logrotate es un motor de políticas, no un job que “debe rotar algo”. El problema es cuando esperabas rotación pero no proporcionaste un disparador o tu estado/criterios dicen “todavía no”.

2) ¿Es el “único error de configuración” realmente solo faltar daily o size?

Sí, en sentido práctico: faltar un disparador (o pensar que rotate N es un disparador) es la causa más común de la no-rotación silenciosa. Los errores de sintaxis suelen gritar; los disparadores faltantes susurran.

3) ¿Debería usar rotación basada en tiempo o en tamaño?

Para volúmenes bajos o moderados, daily está bien. Para alto volumen, usa size o maxsize (a menudo junto con daily) para no esperar hasta medianoche y detener un log descontrolado.

4) ¿Cuál es la diferencia entre size, minsize y maxsize?

size rota cuando el archivo supera ese tamaño (independientemente del calendario). minsize añade un umbral mínimo de tamaño a la rotación basada en tiempo. maxsize fuerza la rotación cuando el tamaño excede un límite incluso si los criterios temporales aún no se cumplen.

5) ¿Cuándo debo usar copytruncate?

Cuando la aplicación no puede reabrir logs y no puedes arreglarla rápidamente. Es un parche de compatibilidad con tradeoffs: posible pérdida de logs en límites de rotación y IO extra. Prefiere rename + señal/reopen para corrección.

6) ¿Por qué el uso de disco sigue alto después de rotar?

Porque el proceso puede seguir escribiendo en un descriptor de archivo eliminado. El sistema de archivos libera espacio solo cuando se cierra el último handle. Usa lsof +L1 para detectarlo y arregla la estrategia de reapertura.

7) ¿Puedo borrar /var/lib/logrotate/status para “resetear” las cosas?

Puedes, pero es una medida tosca. Puede causar rotaciones inesperadas en muchos logs en la siguiente ejecución. Más seguro: edita solo la entrada afectada, o fuerza rotación para una configuración específica con logrotate -f y verifica el comportamiento.

8) ¿Por qué mi sección de logrotate funciona en un entorno pero no en otro?

Diferentes valores globales, diferente comportamiento de include, distintos timers, diferente propiedad de archivos y distinto comportamiento de reapertura de la aplicación. La solución es aburrida: haz los disparadores explícitos, prueba con -d -v y valida con lsof.

9) Añadí daily pero aún no rota. ¿Qué sigue?

Revisa la entrada en el archivo de estado y la salida de debug. Si dice “already rotated”, estás esperando al próximo día. Si el timer no se dispara, arregla la programación systemd. Si fallan permisos, arregla la propiedad/modo o su.

10) ¿Debería rotar archivos cada hora en Ubuntu 24.04?

Solo si realmente lo necesitas. La rotación horaria aumenta la chatarra (más archivos, más trabajo de compresión, más metadatos). Si tu problema es “el disco se llena antes de medianoche”, maxsize suele ser la palanca más adecuada.

Próximos pasos (qué cambiar el lunes por la mañana)

Si estás lidiando con logrotate que no rota en Ubuntu 24.04, haz esto en orden:

  1. Haz el disparador explícito en cada sección personalizada: añade daily o size/maxsize. Deja de confiar en la herencia.
  2. Ejecuta logrotate -d -v en el archivo exacto que te importa y lee las líneas que justifican la decisión. No adivines.
  3. Revisa la entrada del archivo de estado para el log y confirma que coincide con tu expectativa de “última rotación”. Arregla la deriva de tiempo antes de cualquier otra cosa.
  4. Valida el comportamiento de reapertura con lsof +L1. Si ves (deleted), tus rotaciones son cosméticas.
  5. Añade guardarraíles de tamaño para servicios muy ruidosos. La rotación diaria no es un sistema de seguridad; es un evento de calendario.

El objetivo no es “que los logs roten”. El objetivo es “que los logs roten de forma predecible, sin perder eventos, sin picos de CPU sorpresa y sin despertarte en mitad de la noche”. Ese es el estándar.

← Anterior
MySQL vs MariaDB: tablas temporales en disco — cómo detenerlas de verdad
Siguiente →
ZFS zpool iostat -w: Comprender patrones de carga en tiempo real

Deja un comentario