¿Qué es journalctl con systemd en Linux y cómo funciona?

En los últimos tiempos hemos tenido cierta polémica a raíz de la incorporación de systemd en la mayoría de sistemas operativos GNU Linux. Para quien no lo conozca se trata de un conjunto de demonios –daemons-, bibliotecas y herramientas enfocadas a la administración del sistemas, que interactúan con el núcleo o kernel, de nuestro sistemas operativo del Ñu y el Pingüino. La idea es que sustituya al sistema de inicio heredado de los viejos sistemas UNIX. Esto último no ha gustado a muchos administradores ; en cualquier caso hablar de ello no es el fin de este artículo.

Una de las ventajas principales de systemd son las que participan en el proceso y registro del sistema. Por norma general para ver los registros o logs de un servicio del sistema tenemos que consultar, el directorio /var/log y echar un ojo a sus diferentes registros. La solución que encuentra systemd es una administración centralizada de todos los procesos del kernel y los usuarios. El sistema que recopila y administra estos registros es conocida como “journal” o diario.

Dicho diario se implementa con el demonio llamado journald. Este se encarga de manejas todos los mensajes producidos por el kernel, initrd, servicios, etcétera. Vamos a ver entonces como usar la utilidad journalctl, que nos permitirá acceder y manipular dichos datos.

¿Por qué una utilidad centralizada cómo journalctl?

Ya sabéis que soy administrador de sistemas, en mi día a día tengo que consultar continuamente los registros, bien porque ha fallado algún servicio, bien para ver los registros de envío de correo o incluso cuando nuestro sistema produce un “crash” Todo ello es algo farragoso, ya que son registros ubicados en ficheros diferentes y no siempre ubicados en /var/log. Pienso por ejemplo en las aplicaciones Java a medida que ubican sus registros dentro de la carpeta /opt.

Tengo que admitir que la idea de Journalctl me seduce, aunque de momento dicha utilidad, por ejemplo en CentOS y RHEL, sólo está disponible a partir de la versión 7 (la que ha adaptado systemd) A priori al interactuar con los datos utilizando una sola utilidad, los administradores pueden mostrar dinámicamente los datos de registro según sus necesidades.

Empezando a utilizar Journalctl

Antes de nada nos tenemos que asegurar que la zona horaria del sistema esté bien definida. Para ello la systemd incorpora la herramienta timedatectl que nos ayudará a comprobar la hora zona horaria.

Para comprobar, por ejemplo, las zonas horarias disponibles:

  1. timedatectl list-timezones

En mi caso, para ver la zona horaria de la capital de España, sería:

  1. timedatectl list-timezones | grep –i Madrid

Una vez hayamos localizado la zona que nos interesa, la podemos definir utilizando el parámetro set time-zone

  1. timedatectl set-timezone Europe/Madrid

Podemos comprobar la configuración actual, escribiendo:

  1. timedatectl status

En mi caso, en la máquina virtual que estoy utilizando para el artículo:

  1. [root@docker ~]# timedatectl status
  2.       Local time: mié 2017-08-16 19:56:41 CEST
  3.   Universal time: mié 2017-08-16 17:56:41 UTC
  4.         RTC time: mié 2017-08-16 17:56:41
  5.        Time zone: Europe/Madrid (CEST, +0200)
  6.      NTP enabled: yes
  7. NTP synchronized: no
  8.  RTC in local TZ: no
  9.       DST active: yes
  10.  Last DST change: DST began at
  11.                   dom 2017-03-26 01:59:59 CET
  12.                   dom 2017-03-26 03:00:00 CEST
  13.  Next DST change: DST ends (the clock jumps one hour backwards) at
  14.                   dom 2017-10-29 02:59:59 CEST
  15.                   dom 2017-10-29 02:00:00 CET

Ya tenemos la zona horaria definida correctamente, continuemos.

La manera por defecto de ver los logs del demonio journald, es utilizando el comando journalctl, aquí os dejo una muestra:

  1. journalctl

Con el resultado:

  1. ago 16 17:53:02 docker.localdomain kernel: Command line: BOOT_IMAGE=/vmlinuz-3.1
  2. ago 16 17:53:02 docker.localdomain kernel: e820: BIOS-provided physical RAM map:
  3. ago 16 17:53:02 docker.localdomain kernel: BIOS-e820: [mem 0x0000000000000000-0x
  4. ago 16 17:53:02 docker.localdomain kernel: BIOS-e820: [mem 0x000000000009fc00-0x
  5. ago 16 17:53:02 docker.localdomain kernel: BIOS-e820: [mem 0x00000000000f0000-0x
  6. ago 16 17:53:02 docker.localdomain kernel: BIOS-e820: [mem 0x0000000000100000-0x
  7. ago 16 17:53:02 docker.localdomain kernel: BIOS-e820: [mem 0x000000007fff0000-0x
  8. ago 16 17:53:02 docker.localdomain kernel: BIOS-e820: [mem 0x00000000fec00000-0x
  9. ago 16 17:53:02 docker.localdomain kernel: BIOS-e820: [mem 0x00000000fee00000-0x
  10. ago 16 17:53:02 docker.localdomain kernel: BIOS-e820: [mem 0x00000000fffc0000-0x
  11. ago 16 17:53:02 docker.localdomain kernel: NX (Execute Disable) protection: acti
  12. ago 16 17:53:02 docker.localdomain kernel: SMBIOS 2.5 present.
  13. ago 16 17:53:02 docker.localdomain kernel: DMI: innotek GmbH VirtualBox/VirtualB
  14. ago 16 17:53:02 docker.localdomain kernel: Hypervisor detected: KVM

Es cierto, son cientos y miles de datos, al final este resultado no se diferencia de los registros habituales de syslog. Vamos a ver como especificar lo que queremos consultar, en concreto.

Empezemos consultando los registros que se han producido desde el registro más reciente, utilizando el parámetro -b

  1. -- Logs begin at mié 2017-08-16 17:53:02 CEST, end at mié 2017-08-16 10:01:02 CEST. --
  2. ago 16 17:53:02 docker.localdomain systemd-journal[87]: Runtime journal is using 8.0M (max allowed 91.9M, trying to leave 137.9M free of 911.8M available â current limit 91.9M).
  3. ago 16 09:53:02 docker.localdomain kernel: Initializing cgroup subsys cpuset
  4. ago 16 09:53:02 docker.localdomain kernel: Initializing cgroup subsys cpu
  5. ago 16 09:53:02 docker.localdomain kernel: Initializing cgroup subsys cpuacct

El propio journalctlnos inserta una línea indicando que el registro es desde un reinicio del sistema.

Por otra parte el comando los muestra información del arranque actual. Lo cierto es que lo ideal es que también podamos consultar información de reinicios anteriores. Algunas distribuciones esta opción la llevan por defecto. Mi máquina virtual utiliza CentOS 7, por lo que para habilitar la información de arranque de manera persistente, debemos modificar el fichero de configuración, ubicado en /etc/systemd/journald.confg, y cambiar el parámetro “Storage” por “persistent”.

Sería de la siguiente manera:

  1. [Journal]
  2. Storage=persistent
  3. #Compress=yes

Una vez hecho esto, al reiniciar, ya podemos ver el registro de reinicios del sistema:

  1. [root@docker ~]# journalctl --list-boots
  2. -1 45c845be53714a509c817133653b664c mié 2017-08-16 18:49:35 CESTâmié 2017-08-16 18:52:07 CEST
  3.  0 61c4e96daee642b186df167352b10547 mié 2017-08-16 18:52:17 CESTâmié 2017-08-16 18:53:04 CEST

Si queremos volver a utilizar el comando journalctl y que también nos muestre los logs del reinicios anterior, podemos añadir, en este caso, los parámetros journalctl –b -1, de esta manera tendremos los datos el estado actual y lo anteriores al reinicio.

Lo cierto es que con el paso del tiempo se pueden acumular cantidades ingentes de datos, por lo que estaría bien filtrar por fecha. Para ello podemos utilizar los pámetros --since y --until, para mostrar entradas anteriores o siguientes a una fecha, como se observa en el ejemplo.

  1. journalctl --since "2017-08-16 18:46:30" --until "2017-08-16 18:55:00"

Con el resultado:

  1. ago 16 18:49:35 docker.localdomain systemd-journal[88]: Runtime journal is using 8.0M (max allowed 91.9M, trying to lea
  2. ago 16 18:49:35 docker.localdomain kernel: Initializing cgroup subsys cpuset
  3. ago 16 18:49:35 docker.localdomain kernel: Initializing cgroup subsys cpu
  4. ago 16 18:49:35 docker.localdomain kernel: Initializing cgroup subsys cpuacct
  5. ago 16 18:49:35 docker.localdomain kernel: Linux version 3.10.0-514.16.1.el7.x86_64 (builder@kbuilder.dev.centos.org) (
  6. ago 16 18:49:35 docker.localdomain kernel: Command line: BOOT_IMAGE=/vmlinuz-3.10.0-514.16.1.el7.x86_64 root=/dev/mappe
  7. ago 16 18:49:35 docker.localdomain kernel: e820: BIOS-provided physical RAM map:
  8. ago 16 18:49:35 docker.localdomain kernel: BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
  9. ago 16 18:49:35 docker.localdomain kernel: BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved

También se incluyen otros parámetros, como por ejemplo ver los logs del día anterior:

  1. journalctl --since yesterday

O los de hace dos horas:

  1. journalctl --since 17:00 --until "2 hour ago"

Muchas posibilidades, como podemos ver.

Consultar registros de servicios

Entramos en la parte interesante, también podemos ver los registros de un servicios en concreto (unidades). El servidor que estoy utilizando lo utilizo para probar contenedores con Docker, así que vamos a echar un vistazo a su log.

  1. journalctl –u docker-service

Con el siguiente resultado:

  1. ago 16 18:49:55 docker.localdomain systemd[1]: Starting Docker Application Container Engine...
  2. ago 16 18:49:58 docker.localdomain dockerd-current[1058]: time="2017-08-16T18:49:58.318591783+02:00" level=info msg="li
  3. ago 16 18:50:00 docker.localdomain dockerd-current[1058]: time="2017-08-16T18:50:00.415300213+02:00" level=warning msg=

También podemos ver los logs sólo de hoy:

  1. journalctl –u docker.service –since today

Otros usos

También podemos ver los registros de un proceso y sus hijos, agrupados en un número de PID

  1. journalctl _PID=7500

También podemos consultar los mensajes del núcleo o kernel del sistema:

  1. journalctl -k

Al igual que en otros casos anteriores, añadiendo el parámetro -b, veremos los mensajes únicamente del inicio actual:

  1. journalctl –k -b

Como pasa con el comando tail, utilizando el parámetro -n podemos mostrar únicamente un número de líneas, como por ejemplo:

  1. journalctl –n 7

Con el resultado:

  1. ago 16 19:01:01 docker.localdomain run-parts(/etc/cron.hourly)[2539]: finished 0anacron
  2. ago 16 19:01:01 docker.localdomain anacron[2537]: Will run job `cron.daily' in 20 min.
  3. ago 16 19:01:01 docker.localdomain anacron[2537]: Will run job `cron.weekly' in 40 min.
  4. ago 16 19:01:01 docker.localdomain anacron[2537]: Will run job `cron.monthly' in 60 min.
  5. ago 16 19:01:01 docker.localdomain anacron[2537]: Jobs will be executed sequentially
  6. ago 16 19:07:37 docker.localdomain systemd[1]: Starting Cleanup of Temporary Directories...
  7. ago 16 19:07:37 docker.localdomain systemd[1]: Started Cleanup of Temporary Directories.

También podemos filtrar el resultado por prioridad de mensaje, teniendo en cuanta las prioridades:

  • “emerg” (0)
  • ”alert” (1)
  • “crit” (2)
  • “warning” (4)
  • “notice” (5)
  • ”info” (6)
  • “debug” (7)

Por ejemplo:

  1. journalctl –p 3

Con el resultado:

  1. [root@docker ~]# journalctl -p 3
  2. -- Logs begin at mié 2017-08-16 19:49:35 CEST, end at mié 2017-08-16 19:21:03 CEST. --
  3. ago 16 19:49:43 docker.localdomain kernel: intel_rapl: no valid rapl domains found in package 0
  4. ago 16 19:49:46 docker.localdomain systemd[1]: Failed to start Docker Storage Setup.
  5. -- Reboot --
  6. ago 16 19:52:24 docker.localdomain kernel: intel_rapl: no valid rapl domains found in package 0
  7. ago 16 19:52:29 docker.localdomain systemd[1]: Failed to start Docker Storage Setup.

Visualizar registros de dispositivos

Una opción muy útil es que nos permite visualizar sólo los registros de un dispositivo en concreto, como una unidad de disco. Por ejemplo:

  1. journalctl /dev/sda2

Con el resultado, en mi caso:

  1. ago 16 19:52:18 docker.localdomain kernel: scsi 0:0:0:0: Direct-Access     ATA      VBOX HARDDISK    1.0  PQ: 0 ANSI: 5
  2. ago 16 19:52:18 docker.localdomain kernel: sd 0:0:0:0: [sda] 41943040 512-byte logical blocks: (21.4 GB/20.0 GiB)
  3. ago 16 19:52:18 docker.localdomain kernel: sd 0:0:0:0: [sda] Write Protect is off
  4. ago 16 19:52:18 docker.localdomain kernel: sd 0:0:0:0: [sda] Mode Sense: 00 3a 00 00
  5. ago 16 19:52:18 docker.localdomain kernel: sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support
  6. ago 16 19:52:18 docker.localdomain kernel: sd 0:0:0:0: [sda] Attached SCSI disk

Incluso podemos ver el espacio ocupado por los diferentes logs, esto me lo he sacado de la web del replicante 😉

  1. journalctl –disk-usage

Una muestra del resultado en la máquina virtual:

  1. [root@docker ~]# journalctl --disk-usage
  2. Archived and active journals take up 8.0M on disk.

Podemos limitar el tamaño, si este fuera excesivo, modificando el fichero antes comentado /etc/systemd/journald.conf.

Aquí acaba el artículo, espero que en algún momento os sea de utilidad.

Me he servido para el artículo de la información contenida en:

Fuentes | Digitalocean.com | LaMiradaDelReplicante.com

Respecto a los derechos de la imagen de portada | Flickr