Marta escribe a las 09:12: «Anoche, sobre las tres, la web estuvo dando errores. ¿Qué pasó?». Esa pregunta tiene respuesta exacta o no la tiene, y la diferencia la marca lo que hicieras antes de que ocurriera. Un servidor no recuerda nada: lo único que queda de la madrugada es lo que se escribió en algún sitio, con la marca de tiempo correcta, sin que se haya rotado, truncado ni perdido en el reinicio. Esta lección va de eso. Y salda de paso la primera deuda que anuncié al cerrar el Módulo 4: /var/log/tramontana/acceso.log lleva 412 líneas creciendo sin que nadie lo rote, y el día que llene /var se llevará por delante la aplicación entera.
Contenido
- Las dos capas de registro que conviven en Ubuntu
- Facilities y severities de syslog
journalctla fondo- Persistencia del journal
/etc/systemd/journald.confy el control del tamaño- Los ficheros clásicos de
/var/log - Escribir en el log desde tus scripts con
logger logrotate: por qué y cómo- El problema del fichero abierto tras rotar
- Centralización de logs
- Qué NUNCA debe acabar en un log
- Caso Tramontana: rotación y la respuesta para Marta
- Las dos capas de registro que conviven en Ubuntu
En una Ubuntu 24.04 recién instalada hay dos sistemas de registro funcionando a la vez, y entender el reparto evita mucha confusión:
systemd-journald |
rsyslog |
|
|---|---|---|
| Formato | Binario, estructurado, con campos e índice | Texto plano, una línea por evento |
| Dónde escribe | /run/log/journal o /var/log/journal |
/var/log/syslog, auth.log, kern.log… |
| Se consulta con | journalctl |
grep, less, awk |
| Metadatos | Unidad, PID, UID, cgroup, ejecutable, boot ID… | Los que quepan en la línea |
| Rotación y envío remoto | Interna, por tamaño y tiempo; systemd-journal-remote |
logrotate; envío remoto nativo y maduro (TCP/TLS) |
El flujo real: todo lo que un servicio gestionado por systemd escribe en stdout y stderr lo captura journald, junto con lo que llega por el socket /dev/log y los mensajes del kernel. Journald lo guarda con sus metadatos y, además, lo reenvía a rsyslog (ForwardToSyslog=yes), que lo escribe en los ficheros de texto de siempre. Por eso el mismo mensaje aparece en journalctl y en /var/log/syslog.
¿Por qué conservar las dos? El journal es incomparablemente mejor para consultar —filtra por unidad, por prioridad, por arranque, por campo— y los ficheros de texto son mejores para lo que ya sabes hacer con grep, awk y sed, para herramientas de terceros y para el envío remoto. En un servidor real convives con ambos.
- Facilities y severities de syslog
Ese vocabulario viene de los años 80 y sigue vivo porque toda la industria lo entiende. Cada mensaje lleva una facility (de dónde viene) y una severity (cuánto importa).
| Nº | Severity | Cuándo |
|---|---|---|
| 0-1 | emerg / alert |
El sistema es inservible / hay que actuar de inmediato |
| 2 | crit |
Fallo grave: disco, hardware |
| 3 | err |
El nivel que miras a diario |
| 4-5 | warning / notice |
Algo raro que aún no rompe nada / evento significativo pero normal |
| 6-7 | info / debug |
El curso normal de las cosas / solo mientras diagnosticas |
Facilities habituales: auth y authpriv (autenticación: sudo, sshd), cron, daemon (servicios), kern (kernel), mail, syslog, y local0–local7, reservadas para tus aplicaciones. Esa última es la clave práctica: cuando respaldo_tramontana.sh escriba en el log, lo hará con una facility local0 y una severity acorde, y así podrás filtrar tus mensajes sin arrastrar los del sistema.
journalctl a fondo
journalctl a fondoEs la herramienta del día a día y merece la pena aprenderla bien, porque sustituye a media docena de grep.
journalctl # todo, paginado, desde el mensaje más antiguo
journalctl -e # ir directo al final (lo más habitual); -n 50, las 50 últimas
journalctl -f # seguir en vivo, el 'tail -F' del journal; -r invierte el orden
journalctl --no-pager # sin paginador: para scripts y para redirigirFiltrar por unidad, tiempo y prioridad
journalctl -u tramontana.service -f # seguir una unidad en vivo
journalctl -u tramontana.service -u postgresql.service # varias a la vez
journalctl --since "1 hour ago"
journalctl --since yesterday --until "today 06:00"
journalctl --since "2026-08-18 03:00" --until "2026-08-18 03:30"
journalctl -p err # prioridad err o PEOR (0..3)
journalctl -p warning..err # un rango de prioridadesLas expresiones de tiempo aceptan yesterday, today, tomorrow, now, -30min, "2 days ago" y fechas absolutas. Es una de las razones de peso para usar el journal: contestar «qué pasó entre las 3:00 y las 3:30» con ficheros de texto exige un awk con rangos; aquí son dos opciones.
Por arranque y por kernel
journalctl --list-boots # los arranques que se conservan; -b, solo el actual
journalctl -b -1 # el arranque ANTERIOR: qué pasó antes del reinicio
journalctl -k # solo el kernel (como dmesg, pero con historia)
journalctl -k -b -1 -p err # errores de kernel del arranque anteriorjournalctl -b -1 responde a «el servidor se reinició solo esta noche, ¿por qué?», y requiere journal persistente: justo lo del apartado siguiente.
Campos estructurados
Cada entrada del journal no es una línea: es un conjunto de campos. Descúbrelos con:
$ journalctl -u tramontana.service -n 1 -o verbose | head -9
Tue 2026-08-18 03:07:41.882145 CEST [s=9f2c...;i=3a1;b=7d4e...]
_UID=997
_COMM=tramontana
_EXE=/opt/tramontana/releases/3.2.1/bin/tramontana
_SYSTEMD_UNIT=tramontana.service
PRIORITY=3
SYSLOG_IDENTIFIER=tramontana
MESSAGE=db_timeout tras 30s (conexiones_activas=200)Los campos que empiezan por _ los añade journald, y por eso son de fiar: una aplicación no puede falsificarlos. Se usan como filtro:
journalctl _PID=1284 ; journalctl _UID=997
journalctl _COMM=sudo # todo lo que ha hecho sudo; -t filtra por SYSLOG_IDENTIFIER
journalctl _SYSTEMD_UNIT=tramontana.service _PID=1284 # se combinan con ANDFormatos de salida y búsqueda
journalctl -u tramontana.service -o cat # solo el mensaje, sin fecha ni host
journalctl -u tramontana.service -o short-iso # fecha ISO 8601, ordenable
journalctl -u tramontana.service -o json-pretty # para procesar con jq
journalctl -u tramontana.service --grep 'db_timeout' # regex sobre el MESSAGE
journalctl --disk-usage # cuánto ocupa el journal$ journalctl -u tramontana.service --since "2026-08-18 03:00" --until "03:30" -p err -o short-iso | head -3
2026-08-18T03:07:41+0200 srv-tramontana tramontana[1284]: db_timeout tras 30s (conexiones_activas=200)
2026-08-18T03:11:02+0200 srv-tramontana tramontana[1284]: db_timeout tras 30s (conexiones_activas=200)
2026-08-18T03:14:55+0200 srv-tramontana tramontana[1284]: db_timeout tras 30s (conexiones_activas=200)Combinar filtros es la esencia de la herramienta: unidad + ventana temporal + prioridad + formato reproducible, en una sola línea.
- Persistencia del journal
Este es el detalle que sorprende a todo el mundo la primera vez: por defecto, en muchas instalaciones el journal es volátil. Vive en /run/log/journal, que es un tmpfs en RAM, y se pierde entero al reiniciar. Si el servidor se cayó de madrugada y lo reiniciaste, acabas de destruir la única prueba de por qué se cayó.
Si journalctl --list-boots solo muestra una línea, esa es la señal de alarma. Activar la persistencia es trivial y es de lo primero que hay que hacer en un servidor nuevo:
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald$ journalctl --list-boots
-1 7d4e1c... Mon 2026-08-17 08:14:02 CEST—Tue 2026-08-18 04:29:57 CEST
0 9a2b3f... Tue 2026-08-18 04:30:11 CEST—Tue 2026-08-18 12:03:44 CESTLos permisos del directorio (2755 root:systemd-journal) los pone systemd-tmpfiles; ese SGID de 05-02 es lo que permite al grupo systemd-journal —y a adm— leer los ficheros que se creen dentro.
/etc/systemd/journald.conf y el control del tamaño
/etc/systemd/journald.conf y el control del tamañoUn journal persistente sin límites es un /var lleno esperando su turno. Los límites se fijan aquí:
# /etc/systemd/journald.conf (o mejor, un fichero en /etc/systemd/journald.conf.d/)
[Journal]
Storage=persistent
Compress=yes
SystemMaxUse=500M
SystemKeepFree=1G
SystemMaxFileSize=50M
MaxRetentionSec=30day
MaxFileSec=1day
RateLimitIntervalSec=30s
RateLimitBurst=10000
ForwardToSyslog=yes| Directiva | Qué controla |
|---|---|
Storage |
persistent, volatile, auto (persistente si existe /var/log/journal) o none |
SystemMaxUse / SystemKeepFree |
Techo total del journal (por defecto el 10 % de la partición) / espacio que siempre deja libre en /var |
SystemMaxFileSize / MaxRetentionSec |
Tamaño de cada fichero antes de rotar / antigüedad máxima que se conserva |
RateLimitIntervalSec / RateLimitBurst |
Cuántos mensajes por servicio y por intervalo se aceptan |
Ese último par merece un aviso serio: con los valores por defecto, un servicio que emita más de 10 000 mensajes en 30 segundos verá cómo journald descarta el resto en silencio, dejando solo una nota de cuántos ha suprimido. Justo en una tormenta de errores, que es cuando más los necesitas. Si tu aplicación puede ser ruidosa en un incidente, sube RateLimitBurst o desactívalo (RateLimitIntervalSec=0) asumiendo el coste en disco.
sudo cp -a /etc/systemd/journald.conf{,.bak-$(date +%F)} # y luego editar
sudo systemctl restart systemd-journald && journalctl --disk-usage
sudo journalctl --vacuum-size=300M # recortar ahora hasta 300 MiB
sudo journalctl --vacuum-time=15d # o borrar lo anterior a 15 días
- Los ficheros clásicos de
/var/log
/var/log| Fichero | Contenido |
|---|---|
syslog / kern.log |
Cajón general de rsyslog / mensajes del kernel |
auth.log |
Autenticación: sudo, sshd, su, cambios de contraseña. El primero que se mira |
dpkg.log y apt/history.log |
Qué se instaló, cuándo y quién lo pidió (05-03) |
wtmp / btmp / lastlog |
Sesiones abiertas / intentos fallidos / último acceso por cuenta |
Los tres últimos son binarios: un cat sobre ellos escupe basura y puede desconfigurarte el terminal. Se leen con sus herramientas:
$ sudo lastb -n 3 # intentos de acceso FALLIDOS
admin ssh:notty 203.0.113.44 Tue Aug 18 02:14 - 02:14 (00:00)
root ssh:notty 203.0.113.44 Tue Aug 18 02:14 - 02:14 (00:00)
$ last -n 2 # accesos correctos
operador pts/0 10.0.2.1 Tue Aug 18 09:02 still logged inUna ristra de lastb contra root desde una IP extranjera es exactamente el tipo de señal que en 06-03 aprenderás a cortar con fail2ban.
- Escribir en el log desde tus scripts con
logger
loggerTus scripts del Módulo 4 escriben a /var/log/tramontana/cron-copia.log porque no sabías hacer otra cosa. logger manda el mensaje al mismo sitio que el resto del sistema, con su prioridad y su etiqueta:
logger -t respaldo "copia completada" # etiqueta e info
logger -t respaldo -p local0.err "fallo al cifrar" # facility.severity
logger -t respaldo -s -p local0.warning "espacio bajo" # -s: también a stderrAhora modificamos log() y error() de lib/comunes.sh para que, además de su fichero, escriban en el journal:
# lib/comunes.sh — versión conectada al journal
readonly ETIQUETA_LOG="${ETIQUETA_LOG:-$(basename "${0%.sh}")}"
log() {
local mensaje="$*"
printf '[%s] %s\n' "$(date --iso-8601=seconds)" "$mensaje" >>"$FICHERO_LOG"
logger -t "$ETIQUETA_LOG" -p local0.info -- "$mensaje"
}
error() {
local mensaje="$*"
printf '[%s] ERROR: %s\n' "$(date --iso-8601=seconds)" "$mensaje" >&2
logger -t "$ETIQUETA_LOG" -p local0.err -- "$mensaje"
}El -- antes del mensaje evita que un texto que empiece por guion se interprete como opción, siguiendo la disciplina de 04-03. Y como el script ahora corre dentro de tramontana-respaldo.service (05-05), todo lo que escriba a stdout también acaba en el journal de esa unidad, con sus metadatos:
$ journalctl -u tramontana-respaldo.service --since today -o short-iso | tail -3
2026-08-18T04:20:07+0200 srv-tramontana respaldo[8842]: inicio de copia (version=3.2.1)
2026-08-18T04:23:51+0200 srv-tramontana respaldo[8842]: sha256 verificado
2026-08-18T04:23:51+0200 srv-tramontana respaldo[8842]: copia completada en 224sCon eso, la pregunta «¿se hizo la copia anoche?» es un comando, no una investigación.
logrotate: por qué y cómo
logrotate: por qué y cómoUn log sin rotar crece hasta llenar su partición. Cuando /var se llena, la aplicación no puede escribir, la base de datos no puede confirmar transacciones y el propio sistema deja de registrar el desastre. La rotación no es limpieza: es disponibilidad.
logrotate se ejecuta a diario mediante logrotate.timer (systemd, ya sabes leerlo), lee /etc/logrotate.conf y todo lo de /etc/logrotate.d/, y por cada fichero decide si toca rotar.
| Directiva | Qué hace |
|---|---|
daily / weekly / monthly |
Cada cuánto se rota; rotate N, cuántas copias se conservan |
size 100M / maxsize 100M |
Rota al superar ese tamaño ignorando la periodicidad / rota en la ejecución periódica o antes si lo supera |
compress / delaycompress |
Comprime con gzip / a partir de la segunda rotación, dejando .1 sin comprimir |
missingok / notifempty |
Si no existe, no protesta / no rota si está vacío |
create MODO USUARIO GRUPO |
Crea el fichero nuevo con esos permisos |
su USUARIO GRUPO |
Con qué identidad opera logrotate en ese directorio |
sharedscripts |
Ejecuta postrotate una vez aunque el patrón case con varios ficheros |
postrotate … endscript / dateext |
Comandos tras rotar / nombra las copias con la fecha en vez de .1 |
Probar siempre antes de confiar, siguiendo la convención de simular antes de actuar:
sudo logrotate -d /etc/logrotate.d/tramontana # simulación: no toca nada
sudo logrotate -f /etc/logrotate.d/tramontana # forzar la rotación ahora
cat /var/lib/logrotate/status | grep tramontana # cuándo se rotó por última vez
- El problema del fichero abierto tras rotar
Aquí conecta con lo que viste en 05-04 con lsof +L1. Cuando logrotate hace mv acceso.log acceso.log.1, el proceso que lo tenía abierto sigue escribiendo en el mismo inodo: el fichero nuevo se queda a cero para siempre y el viejo sigue creciendo, ahora invisible. Hay dos soluciones y hay que elegir con criterio:
| Solución | Cómo | Ventaja | Inconveniente |
|---|---|---|---|
| Señal al proceso | postrotate con kill -USR1 o systemctl reload |
Sin pérdida de datos, sin copia | La aplicación debe saber reabrir su log |
copytruncate |
Copia el fichero y trunca el original a cero | No requiere nada de la aplicación | Se pierden las líneas escritas entre la copia y el truncado, y duplica el fichero en disco |
La regla: si la aplicación sabe reabrir su log, usa la señal; copytruncate es el último recurso para software que no colabora.
- Centralización de logs
Con un servidor, journalctl basta. Con dos ya no: correlacionar un error del balanceador con otro de la aplicación entrando por SSH en cada máquina es inviable, y además los logs locales desaparecen cuando la máquina se compromete o se pierde, que es justo cuando más falta hacen. Panorama de opciones, sin montarlas aquí:
- rsyslog remoto: la vía clásica y ligera,
*.* @@servidor:6514sobre TCP con TLS. Madura y suficiente para muchos casos. systemd-journal-remote/-upload: conserva la estructura del journal entre máquinas, conjournalctl -mpara consultar varias.- Pilas de observabilidad tipo Loki + Promtail + Grafana, o Elasticsearch + Logstash + Kibana: búsqueda, paneles y alertas, a cambio de operar una infraestructura que consume más recursos que el propio servicio.
Un principio que no cambia: el destino remoto debe ser append-only para quien envía. Si un atacante que entra en srv-tramontana puede borrar los logs del servidor central, la centralización no aporta nada forense.
- Qué NUNCA debe acabar en un log
Advertencia de cumplimiento (RGPD). Los logs se copian, se envían fuera de la máquina, se conservan meses y los lee mucha más gente que los datos de producción. Nunca deben contener contraseñas, tokens, claves de API, cookies de sesión, números de tarjeta ni datos personales de los huéspedes de Tramontana (nombre completo, correo, teléfono, documento de identidad). Registrar
huesped_id=1017es correcto; registrarhuesped=Ana Pérez, [email protected]convierte tu fichero de log en un fichero con datos personales, con todas las obligaciones que eso arrastra. La política de retención —cuánto tiempo se guarda cada tipo de registro— es una decisión legal antes que técnica y debe validarla el responsable de protección de datos o de cumplimiento, teniendo en cuenta que hay registros con mínimos legales de conservación y otros con máximos.
Medidas concretas y baratas: revisa qué escribe tu aplicación en nivel debug antes de activarlo en producción; comprueba que las URL registradas no llevan tokens en la query string; limita /var/log/tramontana al grupo adm con la ACL de 05-02; y fija la retención en logrotate y en journald.conf en lugar de dejarla al azar.
- Caso Tramontana: rotación y la respuesta para Marta
/etc/logrotate.d/tramontana
# /etc/logrotate.d/tramontana — rotación de los logs de Tramontana Reservas
/var/log/tramontana/*.log {
daily
rotate 14
maxsize 100M
compress
delaycompress
missingok
notifempty
dateext
dateformat -%Y-%m-%d
create 0640 svc-tramontana adm
su root adm
sharedscripts
postrotate
/usr/bin/systemctl reload tramontana.service > /dev/null 2>&1 || true
endscript
}Cada línea tiene un porqué: rotate 14 con daily da dos semanas de historia, que es lo acordado con Marta; maxsize 100M protege del pico —un ataque o un bucle de errores pueden generar 100 MiB en una tarde y no queremos esperar a mañana—; create 0640 svc-tramontana adm reproduce exactamente los permisos que necesita la aplicación para escribir y el grupo adm para leer; su root adm es obligatorio cuando el directorio no pertenece a root, o logrotate se niega a actuar por seguridad; sharedscripts evita recargar el servicio cinco veces (una por fichero); y el postrotate usa systemctl reload, que la aplicación traduce en reabrir sus ficheros de log, evitando copytruncate y la pérdida de líneas.
Verificación obligatoria antes de darlo por bueno:
$ sudo logrotate -d /etc/logrotate.d/tramontana 2>&1 | tail -6
rotating pattern: /var/log/tramontana/*.log after 1 days (14 rotations)
considering log /var/log/tramontana/acceso.log
Now: 2026-08-18 12:20
Log needs rotating
rotating log /var/log/tramontana/acceso.log, log->rotateCount is 14
renaming /var/log/tramontana/acceso.log to /var/log/tramontana/acceso.log-2026-08-18$ sudo logrotate -f /etc/logrotate.d/tramontana && ls -l /var/log/tramontana/
-rw-r----- 1 svc-tramontana adm 0 ago 18 12:21 acceso.log
-rw-r----- 1 svc-tramontana adm 41283 ago 18 12:21 acceso.log-2026-08-18
$ sudo lsof +L1 | grep tramontana || echo "sin ficheros borrados en uso: correcto"
sin ficheros borrados en uso: correctoEse último comando es la prueba de que el postrotate funcionó: si la aplicación no hubiera reabierto el fichero, aparecería un (deleted) con NLINK 0.
La respuesta a Marta
Ahora la pregunta de las 03:00 se contesta en tres comandos:
$ journalctl --since "2026-08-18 02:50" --until "2026-08-18 03:30" -p err -o short-iso | head -2
2026-08-18T03:07:41+0200 srv-tramontana tramontana[1284]: db_timeout tras 30s (conexiones_activas=200)
2026-08-18T03:09:12+0200 srv-tramontana tramontana[1284]: db_timeout tras 30s (conexiones_activas=200)
$ journalctl --since "2026-08-18 02:50" --until "2026-08-18 03:30" -p err --no-pager | wc -l
15
$ awk '$2 >= "03:00" && $2 < "03:30" && $5 ~ /^5/' /var/log/tramontana/acceso.log-2026-08-18 | wc -l
9Quince errores en la franja de madrugada, todos el mismo: db_timeout con conexiones_activas=200, que es exactamente el valor de max_conexiones en /etc/tramontana/app.conf. El informe para Marta, con la estructura de siempre —qué sabemos, qué protege y qué no—: «Entre las 03:00 y las 03:30 hubo 15 errores del mismo tipo: la aplicación agotó su límite de 200 conexiones a la base de datos y las peticiones caducaron a los 30 s. Nueve de ellos llegaron a devolver un 5xx a usuarios. No hubo caída del servicio ni pérdida de reservas confirmadas. Los logs ya rotan a diario y se conservan 14 días, así que la próxima vez tendremos la traza completa. Falta averiguar por qué se agotan las conexiones a esa hora, y eso lo medimos en la próxima revisión.»
sudo tee -a /opt/tramontana/HISTORIAL >/dev/null <<'FIN'
2026-08-18 Registros (operador)
- journal persistente (/var/log/journal), SystemMaxUse=500M, MaxRetentionSec=30day
- /etc/logrotate.d/tramontana: daily, rotate 14, maxsize 100M, reload en postrotate
- lib/comunes.sh escribe también al journal vía logger (local0)
- Incidente 03:00-03:30: 15 x db_timeout con conexiones_activas=200. Pendiente análisis.
FINErrores Comunes y Consejos
- Dar por hecho que el journal es persistente. Si
journalctl --list-bootssolo muestra un arranque, estás perdiendo los logs en cada reinicio. Crea/var/log/journalhoy. - Rotar sin avisar al proceso. El fichero nuevo se queda vacío y el viejo sigue creciendo invisible.
lsof +L1lo delata; usapostrotateconreloado, en último caso,copytruncate. - Olvidar
suen unlogrotate.dcuyo directorio no es de root: logrotate lo rechaza por seguridad y deja de rotar en silencio. Compruébalo conlogrotate -d. rotate 0o una retención mínima «para ahorrar disco»: el día del incidente no tendrás nada que mirar. Acuerda la retención con quien la va a necesitar.- Ignorar el rate limiting de journald. En una tormenta de errores puedes perder justo los mensajes que buscas. Revisa
RateLimitBurstsi tu aplicación es ruidosa. catsobrewtmpobtmp. Son binarios: se leen conlastylastb. Y no registres datos personales ni secretos: es una fuga con formato de fichero de texto, replicada en cada copia de seguridad.- Consejo: cualquier script que corra solo debe poder responder «¿se ejecutó y con qué resultado?» con un comando. Si no puede, le falta registro.
Ejercicios
- La franja de madrugada. Escribe un solo comando que muestre, del arranque anterior, únicamente los mensajes de prioridad
erro peor detramontana.serviceproducidos entre las 02:00 y las 06:00, en formato con fecha ISO, y otro que cuente cuántos hubo de cada mensaje distinto. - Rotación para un log de terceros. Una herramienta escribe en
/var/log/analitica/eventos.logcomo el usuarioanalitica, no sabe reabrir su fichero y genera unos 30 MiB al día. Escribe su fichero delogrotate.djustificando cada directiva, y explica qué pierdes con la solución elegida. - Auditoría de accesos. Con lo visto, responde: ¿cuántos intentos fallidos de acceso hubo ayer, desde qué IP, y qué usuarios se intentaron? Da los comandos y di dónde vive cada dato.
Soluciones
1.
journalctl -b -1 -u tramontana.service -p err \
--since "2026-08-18 02:00" --until "2026-08-18 06:00" -o short-iso$ journalctl -b -1 -u tramontana.service -p err --since "2026-08-18 02:00" \
--until "2026-08-18 06:00" -o cat --no-pager | sort | uniq -c | sort -rn
15 db_timeout tras 30s (conexiones_activas=200)
3 backend no disponible (503)-o cat deja solo el texto del mensaje, que es lo que permite agrupar con sort | uniq -c; con el formato normal, la marca de tiempo haría única cada línea. Es el mismo patrón de conteo de 03-05, aplicado ahora al journal.
2.
# /etc/logrotate.d/analitica
/var/log/analitica/eventos.log {
daily
rotate 7
maxsize 50M
compress
delaycompress
missingok
notifempty
copytruncate
su analitica analitica
}daily con rotate 7 da una semana, suficiente para 30 MiB diarios; maxsize 50M cubre un pico sin esperar a mañana; compress con delaycompress ahorra disco sin comprimir el fichero que quizá aún se esté escribiendo; su analitica analitica es imprescindible porque el directorio no es de root; y copytruncate es la única opción viable, ya que la herramienta no sabe reabrir su log y no hay señal que mandarle.
Lo que se pierde: las líneas escritas entre la copia y el truncado, que es una ventana pequeña pero real, y el doble de espacio en disco durante ese instante. No se usa create porque con copytruncate el fichero original nunca se renombra ni se recrea.
3.
$ sudo lastb -s yesterday | head -5 # /var/log/btmp: intentos FALLIDOS
admin ssh:notty 203.0.113.44 Mon Aug 17 23:41 - 23:41 (00:00)
root ssh:notty 203.0.113.44 Mon Aug 17 23:41 - 23:41 (00:00)
$ sudo lastb -s yesterday --time-format notime | awk '{print $3}' | sort | uniq -c | sort -rn
47 203.0.113.44
2 10.0.2.1
$ sudo journalctl -u ssh.service --since yesterday --until today --grep 'Failed password' | wc -l
49Los intentos fallidos viven en dos sitios complementarios: /var/log/btmp (binario, se lee con lastb, guarda usuario, terminal, IP y hora) y el journal de ssh.service, que además da el mensaje exacto y permite filtrar por texto. Cuarenta y siete intentos desde una sola IP en una noche no es un usuario despistado: es un ataque de fuerza bruta, y bloquearlo automáticamente es materia de 06-03.
Conclusión
srv-tramontana ya tiene memoria. Sabes que en Ubuntu conviven dos capas de registro —journald binario y estructurado, rsyslog en texto plano— y por qué el journal reenvía a syslog en lugar de sustituirlo; manejas las ocho severities y las facilities de syslog, incluidas las local0–local7 reservadas para lo tuyo; y exprimes journalctl de verdad: por unidad, en vivo con -f, por ventana temporal con --since/--until, por prioridad con -p, por arranque con -b -1, por kernel con -k, por campos estructurados como _PID y _COMM, con --grep y con formatos short-iso, cat y json-pretty.
Has hecho el journal persistente —sin eso, el reinicio destruye la prueba— y le has puesto techo en journald.conf con SystemMaxUse y MaxRetentionSec, sabiendo que el rate limiting puede tragarse mensajes justo en una tormenta de errores. Reconoces los ficheros clásicos de /var/log y lees wtmp y btmp con last y lastb. Tus scripts escriben en el journal a través de logger desde lib/comunes.sh, y tramontana-respaldo.service responde por sí solo a «¿se hizo la copia anoche?».
Y la deuda del Módulo 4 está pagada: /etc/logrotate.d/tramontana existe, está probado en simulación con logrotate -d, rota a diario conservando catorce días, comprime, recrea el fichero con 0640 svc-tramontana adm y recarga el servicio en postrotate para que ningún proceso siga escribiendo en un inodo huérfano. Sabes qué nunca debe acabar en un log y que la retención es una decisión legal antes que técnica.
Queda la otra mitad de la pregunta de Marta. Sabes qué pasó a las tres de la mañana —quince db_timeout con las 200 conexiones agotadas—, pero no por qué, ni si el servidor iba justo de CPU, de memoria o de disco en ese momento, ni con qué comparar lo que ves hoy. En Monitoreo del Sistema y Optimización del Rendimiento aprenderás el método USE aplicado a los cuatro recursos, interpretarás de verdad el load average, vmstat, free -h, iostat -xz y sar, sabrás cuándo ha actuado el OOM killer y por qué, establecerás una línea base de srv-tramontana, y aplicarás un procedimiento numerado de diagnóstico a la queja de Marta de que «la web va lenta por las mañanas» — donde descubrirás que la copia de seguridad y esas 200 conexiones tienen más que ver de lo que parece.
Curso de Linux: De Principiante a Administrador de Sistemas
Módulo 1: Introducción a Linux
- ¿Qué es Linux?
- Historia de Linux
- Distribuciones de Linux
- Instalando Linux
- Primer Contacto con el Sistema
- Estructura del Sistema de Archivos de Linux
Módulo 2: Comandos Básicos de Linux
- Introducción a la Línea de Comandos
- Obtener Ayuda y Documentación del Sistema
- Navegando el Sistema de Archivos
- Operaciones con Archivos y Directorios
- Visualización y Edición de Archivos
- Enlaces Duros y Simbólicos
- Permisos y Propiedad de Archivos
Módulo 3: Habilidades Avanzadas en la Línea de Comandos
- El Entorno del Shell: Variables, Alias e Historial
- Uso de Comodines y Expresiones Regulares
- Búsqueda de Archivos y Contenido: find, locate y grep
- Tuberías y Redirección
- Procesamiento de Texto: cut, sort, uniq, sed y awk
- Gestión de Procesos
- Programación de Tareas con Cron
- Comandos de Redes
Módulo 4: Scripting en Shell
- Introducción al Scripting en Shell
- Variables y Tipos de Datos
- Entrada, Salida y Argumentos de un Script
- Estructuras de Control
- Funciones y Librerías
- Depuración y Manejo de Errores
- Scripts de Producción: Buenas Prácticas
Módulo 5: Administración del Sistema
- Gestión de Usuarios y Grupos
- sudo y Permisos Especiales
- Gestión de Paquetes
- Gestión de Discos
- systemd y la Gestión de Servicios
- Registros del Sistema: journald y syslog
- Monitoreo del Sistema y Optimización del Rendimiento
- Respaldo y Restauración
Módulo 6: Redes y Seguridad
- Configuración de Redes
- SSH y Acceso Remoto
- Firewall y Seguridad Perimetral
- Sistemas de Detección de Intrusos
- Gestión de Secretos y Certificados TLS
- Asegurando Sistemas Linux
Módulo 7: Temas Avanzados
- El Proceso de Arranque y la Recuperación del Sistema
- Diagnóstico Avanzado: strace, perf y eBPF
- Optimización del Kernel de Linux
- Virtualización con Linux
- Contenedores de Linux y Docker
- Automatización con Ansible
- Alta Disponibilidad y Balanceo de Carga
