Articles

Cómo funciona Log4J2: 10 Formas de Sacarle el máximo partido

Log4j2 es la versión actualizada de la popular e influyente biblioteca log4j, utilizada ampliamente en todo el ecosistema Java durante tantos años. Versión 2.x mantiene todas las características de registro de su predecesor y se basa en esa base con algunas mejoras significativas, especialmente en el área de rendimiento.

Y, por supuesto, dado lo instrumental que es el registro para cualquier aplicación, tanto para fines de auditoría como de depuración, elegir una biblioteca de registro sólida es una decisión bastante importante.

En las siguientes secciones, vamos a echar un vistazo a por qué la biblioteca log4j2 es una gran opción para esa decisión y cómo podemos usarla en una aplicación.

Configuración básica de Log4j2

Para comenzar a usar log4j2 en su proyecto, simplemente debe agregar la dependencia log4j-core. Si estás usando Maven, puedes agregar la siguiente dependencia a tu pom.archivo xml:

Y si estás trabajando con Gradle, necesitas agregar la dependencia a la compilación.archivo gradle:

dependencies { compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.8.2'}

Fuera de la caja, log4j2 proporcionará automáticamente una configuración simple, si no la define explícitamente usted mismo. La configuración predeterminada se registra en la consola a un nivel de ERROR o superior.

Para iniciar el registro de mensajes utilizando esta configuración básica, todo lo que necesita hacer es obtener una instancia de registrador utilizando la clase LogManager:

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

A continuación, puede utilizar el objeto logger con métodos correspondientes al nivel de registro que desee:

logger.error("This is an error message");

Personalizar la configuración de Log4j2

Se puede crear una configuración de log4j2 personalizada mediante programación o a través de un archivo de configuración.

La biblioteca admite archivos de configuración escritos en XML, JSON, YAML, así como el .formato de propiedades. Aquí, vamos a usar XML para discutir todos los ejemplos principalmente.

En primer lugar, puede anular la configuración predeterminada simplemente creando un log4j2.archivo xml en la ruta de clase:

Echemos un vistazo más de cerca a las etiquetas utilizadas en esta sencilla configuración:

  • Configuración: el elemento raíz de un archivo de configuración log4j2; el atributo status representa el nivel en el que se deben registrar los eventos log4j internos
  • Anexadores: este elemento contiene una lista de anexadores; en nuestro ejemplo, se define un anexador correspondiente a la consola del sistema
  • Registradores: este elemento contiene una lista de instancias de registradores. El elemento Raíz es un registrador estándar que emite todos los mensajes

Es importante entender que el registrador raíz es obligatorio en todas las configuraciones. Como se mencionó, si no proporciona uno, se configurará automáticamente de forma predeterminada con un anexador de consola y el nivel de registro de ERRORES.

Configurar los agregadores

En la arquitectura log4j2, un agregador es básicamente responsable de enviar mensajes de registro a un determinado destino de salida.

Estos son algunos de los tipos de anexadores más útiles que proporciona la biblioteca:

  • ConsoleAppender – registra los mensajes en la consola del sistema
  • FileAppender – escribe los mensajes de registro en un archivo
  • RollingFileAppender – escribe los mensajes en un archivo de registro móvil
  • JDBCAppender – utiliza una base de datos relacional para los registros
  • AsyncAppender – contiene una lista de otros appenders y determina los registros para que se escriban en un hilo separado

Para entender mejor cómo funcionan los anexadores, veamos algunos ejemplos de configuración.

El RollingFileAppender

Registrar todo en un solo archivo no es, por supuesto, lo ideal. Por lo general, es mucho mejor pasar el archivo de registro activo con regularidad, que es exactamente lo que hace RollingFileAppender.

También podrá ir más allá de lo básico con este tipo de appender y configurar tanto una política de activación personalizada como una estrategia de rollover.

La directiva de activación determina cuándo se rueda el archivo de registro, lo que significa que se crea un nuevo archivo, mientras que la estrategia de rollover determina cómo se rueda el archivo.

Como ejemplo rápido, vamos a configurar un appender que cree un nuevo archivo de registro basado en 3 políticas:

  • OnStartupTriggeringPolicy – se crea un nuevo archivo de registro cada vez que se inicia la JVM
  • TimeBasedTriggeringPolicy – el archivo de registro se rueda en función de un patrón de fecha/hora
  • SizeBasedTriggeringPolicy – el archivo se rueda cuando alcanza un cierto tamaño

La configuración utilizará la estrategia DefaultRolloverStrategy:

Puede ver cuán flexible es este estilo de configuración y cómo puede ajustar la semántica exacta de su estrategia de registro, hasta el último detalle.

El appender JDBC

Como su nombre indica, este appender utiliza JDBC para escribir registros en una base de datos relacional.

Para esta configuración, debe definir una fuente de conexión, que puede ser una fuente de datos JNDI o una fábrica de conexión personalizada. El registrador utiliza la fuente de conexión para obtener conexiones JDBC, por lo que es importante utilizar un grupo de conexiones para un mejor rendimiento.

Para configurar el appender en el archivo de configuración XML, puede usar la etiqueta JDBC:

Como puede ver, la fuente de datos JNDI se especifica simplemente utilizando el atributo jndiName de la etiqueta de origen de datos. Junto con la fuente de conexión, puede definir la tabla y las columnas que se utilizarán para almacenar los datos de registro.

El FailoverAppender

Finalmente, echemos un vistazo al FailoverAppender; esto define un appender principal y una lista de copias de seguridad que intervendrán para manejar el registro en caso de que el primario falle.

Por ejemplo, puede configurar un servidor JDBCAppender principal, con un servidor secundario the RollingFile y los servidores de consola en caso de que no se pueda establecer una conexión a la base de datos:

En un entorno de producción, siempre es una buena idea tener una estrategia de conmutación por error para su mecanismo de registro.

Configurar diseños

Mientras que los agregadores son responsables de enviar mensajes de registro a un destino, los agregadores utilizan los diseños para definir cómo se formateará un mensaje de registro.

Aquí hay una breve descripción de algunos de los diseños más utilizados que ofrece log4j2:

  • PatternLayout-configura los mensajes de acuerdo con un patrón de cadena
  • JsonLayout – define un formato JSON para mensajes de registro
  • CsvLayout – se puede usar para crear mensajes en formato CSV

El PatternLayout

El primer tipo de diseño que vamos a ver es el PatternLayout. Esta es una solución bastante flexible que le da mucho control sobre la salida final del mensaje de registro.

El mecanismo es impulsado principalmente por un patrón de conversión que contiene especificadores de conversión. Cada especificador comienza con el signo%, seguido de modificadores que controlan cosas como el ancho y el color del mensaje, y un carácter de conversión que representa el contenido, como la fecha o el nombre del hilo.

Veamos un ejemplo de configuración de un diseño de patrones que configura líneas de registro para mostrar la fecha, el hilo, el nivel de registro y el mensaje de registro con diferentes colores para diferentes niveles de registro:

Vale la pena comprender en detalle estos especificadores, así que echemos un vistazo más de cerca:

  • %d{HH:mm:ss.SSS} – muestra la fecha del evento de registro en el formato especificado
  • %t – muestra el nombre del subproceso
  • %level – muestra el nivel de registro del mensaje
  • %highlight{%level} – se utiliza para definir los colores para el patrón entre corchetes rizados
  • %msg%n – muestra el mensaje de registro

La salida mostrará los niveles de registro con diferentes colores:

Puede leer más conjunto de opciones para definir patrones en la documentación de log4j2 en PatternLayout.

Los datos de registro de JsonLayout

que utilizan el formato JSON tienen algunas ventajas significativas, como hacer que los registros sean más fáciles de analizar y procesar mediante herramientas de registro en el futuro.

Para configurar JSONLayout en log4j2, simplemente puede definir la etiqueta correspondiente:

<JSONLayout complete="true" compact="false"/>

La configuración complete = true producirá un documento JSON bien formado:

Para poder producir JSON, también debe agregar la biblioteca jackson-databind a la ruta de clase:

Configuración de filtros

Los filtros en log4j2 se utilizan para determinar si un mensaje de registro debe procesarse o omitirse.

Se puede configurar un filtro para toda la configuración o a nivel de registrador o de anexador.

La biblioteca proporciona varios tipos de filtros que se pueden utilizar:

  • BurstFilter-controla el número de eventos de registro permitidos
  • DynamicThresholdFilter – filtra las líneas de registro en función de ciertos atributos
  • RegexFilter – filtra los mensajes en función de si coinciden con una expresión regular

Puede, por ejemplo, controlar la velocidad con la que se permite a la aplicación registrar datos.

Para hacerlo, puede configurar un filtro de explosión y aplicarlo a los mensajes de información:

<Filters> <BurstFilter level="INFO" rate="10" maxBurst="100"/></Filters>

Esto ignorará selectivamente el control del tráfico de los mensajes de nivel de información y de abajo, mientras se asegura de que no está perdiendo ninguno de los mensajes más importantes de arriba.

En este caso, rate define el promedio de mensajes de registro que se deben procesar por segundo, y maxBurst controla el tamaño total de la ráfaga de tráfico antes de que el filtro comience a eliminar las entradas de registro.

De manera similar, podemos configurar el appender solo para aceptar mensajes de registro que coincidan con una expresión regular específica:

<Appenders> <JDBC name="JDBCAppender"> <RegexFilter regex="*jdbc*" onMatch="ACCEPT" onMismatch="DENY"/> </JDBC></Appenders>

En general, este mecanismo de filtrado se puede usar con gran precisión para asegurarse de que cada appender en su configuración general de registro esté rastreando la información correcta. La capacidad de registrar solo información muy específica y relevante generalmente conduce a un análisis de causa raíz muy rápido, especialmente en sistemas complejos, especialmente cuando se combina con una poderosa herramienta de visualización de registros.

Configurando Loggers

Además del logger Raíz, también podemos definir elementos de Logger adicionales con diferentes niveles de registro, agregadores o filtros. Cada registrador requiere un nombre que se puede usar más tarde para hacer referencia a él:

<Loggers> <Logger name="RollingFileLogger"> <AppenderRef ref="RollingFileAppender" /> </Logger></Loggers>

Para escribir mensajes de registro utilizando este Registrador en particular, puede obtener una referencia a él utilizando la clase LogManager:

Logger rfLogger = LogManager.getLogger("RollingFileLogger");rfLogger.info("User info updated");

Otra forma muy común de estructurar la jerarquía de estos registradores se basa en la clase Java:

Logger logger = LogManager.getLogger(MyServiceTest.class);

El uso de búsquedas

Las búsquedas representan una forma de insertar valores externos en la configuración de log4j2. Ya hemos visto un ejemplo de la búsqueda de fechas en la configuración de RollingFileAppender:

<RollingFile name="RollingFileAppender" fileName="logs/app.log" filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">

La búsqueda ${date:yyy-MM} insertará la fecha actual en el nombre del archivo, mientras que la anterior $ es un carácter de escape, para insertar la expresión de búsqueda en el atributo filePattern.

también puede insertar propiedades del Sistema de valores en log4j2 de configuración utilizando el formato ${sys:property_name}:

<File name="ApplicationLog" fileName="${sys:path}/app.log"/>

Otro tipo de información y de búsqueda de inserción es el entorno Java de la información:

<PatternLayout header="${java:version} - ${java:os}"> <Pattern>%d %m%n</Pattern></PatternLayout>

Usted puede encontrar más detalles sobre el tipo de datos que se puede insertar a través de búsquedas en la log4j2 documentación.

Configuración programática

Además de los archivos de configuración, log4j2 también se puede configurar mediante programación. Hay varias formas de hacerlo:

  • crear una ConfiguraciónFactory personalizada
  • usar la clase Configurator
  • modificar la configuración después de la inicialización
  • combinar archivos de propiedades y configuración programática

Echemos un vistazo a cómo configurar un diseño y un appender mediante programación:

A continuación, puede definir un logger utilizando la clase LoggerConfig, asociarle el appender y actualizar la configuración:

Luego, puede comenzar a usar el registrador como de costumbre:

Logger pLogger = LogManager.getLogger("programmaticLogger");pLogger.info("Programmatic Logger Message");

Este estilo de API fluida puede conducir a un desarrollo e iteración más rápidos en configuraciones de registro más complejas porque ahora se beneficia de los beneficios de trabajar directamente con código Java.

Sin embargo, dado que el XML todavía puede ser más legible y compacto, a menudo puede desarrollar la configuración mediante programación y luego convertirlo a XML cuando todo esté listo.

Niveles de registro personalizados

Los niveles de registro integrados para log4j2 son:

  • APAGADO
  • FATAL
  • ERROR
  • ADVIERTEN
  • INFO
  • DEBUG
  • SEGUIMIENTO
  • TODOS

además De estos, también se puede definir un registro personalizado de nivel de acuerdo a las necesidades de su aplicación.

Por ejemplo, para definir este nuevo nivel de registro, puede hacer uso del Nivel.API forName (): especifica el nuevo nombre de nivel y un entero que representa el lugar del nivel en la jerarquía de niveles de registro:

Level myLevel = Level.forName("NEW_LEVEL", 350);

Para determinar qué valor entero usar, puede echar un vistazo a los valores definidos para los otros niveles de registro en la documentación de log4j2:

El valor 350 pone el nivel entre WARN e INFO, lo que significa que los mensajes se mostrarán cuando el nivel se establezca en INFO o superior.

Para registrar un mensaje a nivel personalizado, debe usar el método log ():

logger.log(myLevel, "Custom Level Message");

La configuración XML equivalente podría ser:

<CustomLevels> <CustomLevel name="NEW_XML_LEVEL" intLevel="350" /></CustomLevels>

Luego se puede usar a través de la API de registro estándar:

logger.log(Level.getLevel("NEW_XML_LEVEL"),"Custom XML Level Message");

Los nuevos niveles personalizados se mostrarán de la misma manera que los estándares:

11:28:23.558 NEW_LEVEL - Custom Level Message11:28:23.559 NEW_XML_LEVEL - Custom XML Level Message

Migrando desde Log4j 1.x

Si está migrando una aplicación utilizando el 1.versión x de la biblioteca a la actual 2.versión x, hay un par de rutas que puede seguir:

  • use el log4j 1.x bridge
  • actualizar manualmente la API y la configuración

Usando el puente es trivial. Solo necesita reemplazar la dependencia log4j con la biblioteca log4j-1.2-api:

Si bien este es el método más rápido, tiene la desventaja de estar limitado en el tipo de configuración que se puede convertir.

El método manual es, por supuesto, más trabajo, pero eventualmente conducirá a una solución de registro más flexible y potente.

Estos son algunos de los cambios más comunes que tendrá que hacer:

Conclusión

Los archivos de registro son críticos en cualquier entorno de producción, y elegir una buena solución de registro puede ser la diferencia entre pasar 5 minutos y pasar un día completo para comprender un problema en la producción.

Log4j2 es una solución de registro potente y robusta para aplicaciones Java modernas, con una amplia gama de opciones de configuración.

Permite una fácil configuración de prácticas recomendadas de registro avanzadas, como archivos móviles, diferentes tipos de destinos de salida de registro, soporte para formatos de registro estructurados como JSON o XML, uso de múltiples registradores y filtros, y niveles de registro personalizados.

Finalmente, cuando necesite ir más allá del análisis manual de datos de registro, definitivamente revise las capacidades de registro incluidas en el APM de rastreo.