Cambiar los niveles de log de forma dinámica sin reiniciar la aplicación con Log4j

Escrito por picodotdev el .
java planeta-codigo
Enlace permanente Comentarios

Ocurre un bug en producción o en un entorno de pruebas se desea obtener más información. Actualizar el archivo de trazas para obtener más información requiere modificar el archivo de configuración, desplegarlo en el entorno y reiniciar la aplicación, este proceso consume tiempo dependiendo del nivel de automatización de la organización. Para reducir el tiempo necesario para obtener la información con Log4j hay dos posibilidades para cambiar dinámicamente los niveles de trazas de la aplicación sin necesidad de reiniciarla.

Java

Las trazas son muy útiles para tener un registro de lo que ha realizado una aplicación, también son muy útiles en tiempo de desarrollo y para depurar la aplicación. Cada traza se emite con un nivel de prioridad, en el momento de desarrollo puede que nos interese las trazas de más bajo nivel de debug, trace o info, en el entorno de producción donde la aplicación debe funcionar correctamente las trazas de debug e info se omiten y las aplicaciones se suele configuran con un nivel mínimo de warn o error para que las trazas sean registradas.

Sin embargo, cuando se descubre un error en producción o se quiere obtener más información con los niveles de info de qué es lo que está ocurriendo la aplicación requiere al menos cambiar el archivo de configuración de las trazas con su commit al un repositorio de control de versiones, la actualización del archivo de configuración desplegado en el entorno de producción y un reinicio de la aplicación. Este proceso de desarrollo y operaciones requiere tiempo más o menos dependiendo del nivel de automatización que posee la aplicación, en cualquier caso consume tiempo de personas y retrasa el tiempo necesario para obtener información y por tanto para resolver el problema.

¿Te imaginas lo bueno que sería que cuando hay un bug en producción o se necesita poder reconfigurar los niveles de trazas de dinámicamente sin reiniciar la aplicación ni despliegues? Una de las librerías más populares en Java para emitir trazas Log4j permite cambiar de forma dinámica el nivel de las trazas para cada logger.

El requisito para que cambiar el nivel de las trazas sea útil es que deben estar incluidas previamente en la aplicación, con un nivel de traza y mensaje adecuado.

Hay dos posibilidades:

  • Utilizar la opción monitorInterval con la que Log4j monitoriza según el tiempo configurado el archivo de configuración de las trazas para conocer si ha tenido cambios y reconfigurar los niveles de trazas cuando detecta cambios.
  • Utilizar la clase Configurator. Esta clase no es parte de la API pública lo que implica que puede cambiar pero permite cambiar los niveles de trazas de forma programática.

En este ejemplo de código se utiliza la clase Configurator.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package io.github.picodotdev.blogbitix.log4j;

...

public class Main {

    private static final Logger logger = LogManager.getLogger(Main.class);

    public static void main(String[] args) {
        ...
        Main.changeLogLevelDynamically();
    }

    ...

    private static void changeLogLevelDynamically() {
        Configurator.setLevel(logger.getName(), Level.ERROR);
        logger.info("info trace");
        logger.error("error trace");

        logger.error("");

        Configurator.setLevel(logger.getName(), Level.INFO);
        logger.info("info trace");
        logger.error("error trace");
    }
}
Main.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
configuration:
  status: warn

  ...

  loggers:
    root:
      level: info
      appenderRef:
        ref: STDOUT
log4j2.yaml

El nivel de trazas según se inicia la aplicación para el logger es info por configuración, según se ejecuta el programa se cambia el nivel de trazas a error y finalmente se restablece el nivel de trazas a info. Se observa que cuando el nivel de las trazas está a nivel error la traza de nivel info no se emite, como es lo esperado. Al restablecer el nivel a info se emiten ambas trazas.

1
2
3
4
2020-02-28 19:43:38,465  ERROR                    io.github.picodotdev.blogbitix.log4j.Main error trace
2020-02-28 19:43:38,465  ERROR                    io.github.picodotdev.blogbitix.log4j.Main 
2020-02-28 19:43:38,465  INFO                     io.github.picodotdev.blogbitix.log4j.Main info trace
2020-02-28 19:43:38,466  ERROR                    io.github.picodotdev.blogbitix.log4j.Main error trace
System.out

Para cambiar el nivel de trazas de una aplicación de forma programática se puede ofrecer una interfaz JMX en la aplicación o si se trata de una aplicación web una página de configuración que ofrezca la funcionalidad.

La reconfiguración de los niveles de trazas deben ser temporales ya que la aplicación dependiendo de su carga emite más trazas que con los niveles warn y error. Si las trazas se guardan en un archivo, guardar mayor cantidad de ellas hace que su tamaño pueda ser significativo e incluso llenar el almacenamiento provocando malfuncionamiento en la aplicación. Para evitar que el archivo de trazas llene el almacenamiento persistente es posible limitar por tamaño, por fecha y rotar los archivos de trazas.