Tutorial de ejemplo de Log4j2 – Configuración, Niveles, Apendices

Bienvenido al Tutorial de Ejemplo de Apache Log4j2. Si le preguntas a un desarrollador experto sobre lo más molesto de una aplicación, la respuesta podría estar relacionada con el registro. Si no hay un registro adecuado en una aplicación, el mantenimiento será una pesadilla. La mayoría de las aplicaciones pasan por pruebas de desarrollo, pruebas unitarias, pruebas de integración. Pero cuando se trata de producción, siempre te enfrentarás a escenarios y excepciones únicas. Entonces, la única forma de averiguar qué sucedió en un caso específico es depurar a través de los registros. Muchos marcos proporcionan algún tipo de registro predeterminado, pero siempre es mejor optar por el mecanismo de registro estándar de la industria. Apache Log4j es uno de los marcos de registro más ampliamente utilizados. Apache Log4j 2 es la siguiente versión, que es mucho mejor que Log4j.

Tutorial de Ejemplo de Log4j

En este Tutorial de Ejemplo de Log4j2, aprenderás cómo empezar con Apache Log4j2. También exploraremos la arquitectura de Log4j2, la configuración de log4j2, los niveles de registro de log4j2, los apéndices, los filtros y mucho más.

  1. Visión General de Log4j2
  2. Arquitectura de Log4j2
  3. Configuración de Log4j2
  4. Niveles de Log4j2
  5. Búsquedas de Log4j2
  6. Apéndices de Log4j2
  7. Filtros de Log4j2
  8. Diseños de Log4j2
  9. ¿Qué nivel de Log4j2 debería usar?
  10. Resumen del Tutorial de Log4j2

Visión General de Log4j2

Usar la API de registro en la aplicación no es un lujo, es una necesidad. Log4j es una biblioteca de código abierto que se publica y se licencia bajo Apache Software. Puede depurar una aplicación usando la depuración de Eclipse u otras herramientas, pero eso no es suficiente y factible en un entorno de producción. El mecanismo de registro le proporcionará varios beneficios que no encontrará en la depuración normal.

Category / Operation (Debugging, Logging) Debugging Logging
Human Intervention There’s a need for human intervention No need for human intervention
Persistent Medium Can’t be integrated with persistent storage Can be integrated with persistent storage (Files, Database, NoSQL database, etc.)
May used for Auditing Can’t be used for achieving auditing Can be used for achieving auditing if it’s used efficiently
Sufficient for complicated structure and flow Not sufficient; you may get lost with flow. Sufficient
Productivity Less productive More productive

Como puede ver arriba, el uso del mecanismo de registro será más eficiente con un menor costo de mantenimiento. Apache Log4j es la herramienta líder para el registro en aplicaciones Java, por lo que debería usarlo.

Arquitectura de Log4j2

Antes de proceder con el tutorial de ejemplo de Log4j, es bueno examinar la arquitectura de Log4j2. La siguiente imagen muestra las clases importantes en la API de Log4j2. Aquí está la explicación detallada de la arquitectura mostrada anteriormente:

  • Las aplicaciones solicitarán a LogManager un Logger con un nombre específico.

  • LogManager ubicará el LoggerContext apropiado y luego obtendrá el Logger de él.

  • Si el Logger aún no ha sido creado, será creado y asociado con LoggerConfig según tres opciones a continuación:

    1. La instancia del Logger será creada y asociada con el LoggerConfig que tenga el mismo nombre. Por ejemplo, App.class en getLogger(App.class) será evaluado como un String com.journaldev.App. El nombre del LoggerConfig es idéntico al nombre de la clase completamente calificada (componente de software).
    2. La instancia del Logger será creada y asociada con el LoggerConfig que tenga el mismo paquete principal de los Loggers. Por ejemplo com.journaldev en getLogger("com.journaldev")
    3. La instancia del Logger será creada y asociada con el Root LoggerConfig. Se utilizará el Root LoggerConfig cuando no haya un archivo de configuración o cuando se esté obteniendo un logger con un nombre no definido en las declaraciones del logger.
  • Los objetos Configurador de Registros se crean a partir de la declaración de Registro en el archivo de configuración. El Configurador de Registros también se utiliza para manejar Eventos de Registro y delegarlos a sus Agregadores de Log4j2 definidos.

  • El registro raíz es un caso excepcional en términos de su existencia. Siempre existe y está en la parte superior de cualquier jerarquía de registros.

  • Puede obtener el registro raíz mediante las siguientes declaraciones:

    Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
    Logger logger = LogManager.getRootLogger();
    
  • Los nombres de los registros de log4j2 son sensibles a mayúsculas y minúsculas.

  • Excepto el registro raíz, todos los registros se pueden obtener pasando su nombre a LogManager.getLogger().

  • LoggerContext es un punto vocal para el sistema de registro ya que puedes tener múltiples LoggerContexts dentro de tu aplicación. Para cada LoggerContext se debe establecer una configuración activa.

  • La configuración de Log4j2 contiene todos los activos del sistema de registro; LoggerConfig(s), Appender(s), Filter(s) y muchos otros.

  • Llamar a LogManager.getLogger() pasando el mismo nombre siempre devolverá la referencia para la misma instancia exacta del registrador.

  • La configuración del sistema de registro se realiza típicamente durante la inicialización de la aplicación. Esto puede tomar diferentes formas; programáticamente o leyendo un archivo de configuración log4j2.

Cada registrador está asociado con un objeto LoggerConfig, un conjunto de objetos LoggerConfig conforma una jerarquía de registradores. Este concepto se conoce como Jerarquía de Registros. Jerarquía de Registros está compuesta por un conjunto de objetos LoggerConfig con una relación padre-hijo. El elemento superior en cada Jerarquía de Registros es el Registrador Raíz. Si Log4j2 no encuentra el archivo de configuración, solo se usará el Registrador Raíz para registrar con el nivel de registro ERROR. La siguiente imagen muestra el mensaje de advertencia que recibirá en este caso. Error StatusLogger No se encontró archivo de configuración de log4j2. Usando la configuración predeterminada: registrando solo errores en la consola. La tabla a continuación muestra la relación padre-hijo en la Jerarquía de Registros.

LoggerConfig (Is A) Root com com.journaldev com.journaldev.logging
Root X Child descendant descendant
com Parent X Child descendant
com.journaldev Ancestor Parent X Child
com.journaldev.logging Ancestor Ancestor Parent X

Para aclarar la relación padre-hijo, la tabla anterior se leería de la siguiente manera:

  • Root es un padre para com.
  • Root es un ancestro para com.journaldev.
  • Root es un ancestro para com.journaldev.logging.
  • com es un hijo para Root.
  • com es un padre para com.journaldev.
  • com es un ancestro para com.journaldev.logging.
  • com.journaldev.logging es un hijo para com.journaldev y así sucesivamente.

Una instancia de LoggerConfig se considera ancestro de otra LoggerConfig si su nombre seguido de un punto es un prefijo del nombre del descendiente. Una instancia de LoggerConfig se considera padre de otra LoggerConfig si no hay nombres intercalados entre ambas.

Configuración de Log4j2

Hay muchas formas de usar la configuración de Log4j2 en tu aplicación.

  1. Usando un archivo de configuración escrito en XML, JSON, YAML o archivo de propiedades.
  2. Programáticamente, creando una fábrica de configuración e implementación de configuración.
  3. Programáticamente, llamando a las APIs expuestas en la interfaz de configuración.
  4. Programáticamente, llamando a métodos en la clase interna del registrador.

Nos enfocaremos principalmente en el archivo de configuración. Sin embargo, es bueno conocer también el enfoque de programación, en caso de que desees configurar una estrategia de registro específica para algún Logger específico. En primer lugar, consideremos el caso en el que no proporcionaste un archivo de configuración. La implementación de Log4j2 asume que hay una variable del sistema llamada log4j.configurationFile para señalar la ubicación del archivo de configuración de log4j2.

package com.journaldev;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class App
{
    public static void main( String[] args ) {
    	Logger logger = LogManager.getRootLogger();
    	logger.trace("Configuration File Defined To Be :: "+System.getProperty("log4j.configurationFile"));
    }
}

A simple log4j2 configuration file will look like below. configuration.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="trace">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

Y aquí está la explicación detallada del código enumerado anteriormente:

  • La aplicación ha referenciado el logger Raíz llamando al método getRootLogger de LogManager.
  • La referencia del registrador desde LogManager ha iniciado el sistema Log4j.
  • Log4j inspeccionará la propiedad del sistema log4j.configurationFile para determinar el archivo de configuración de log4j2. La configuración de Log4j puede estar escrita en JSON, YAML y XML.
  • Podemos establecer la propiedad del sistema log4j.configurationFile mediante System.setProperties("log4j.configurationFile","RUTA_DEL_ARCHIVO") o pasándola como un parámetro JVM como se ve en la figura a continuación. También se observa el prefijo del protocolo File.

  • En caso de que no se haya definido ninguna propiedad del sistema, el orden de configuración sigue la siguiente precedencia:
    • La fábrica de configuración de propiedades buscará log4j2-test.properties en la ruta de clases.
    • La fábrica de configuración YAML buscará log4j2-test.yaml o log4j2-test.yml en la ruta de clases.
    • La fábrica de configuración JSON buscará log4j2-test.jsn o log4j2-test.json en la ruta de clases.
    • La fábrica de configuración XML buscará log4j2-test.xml en la ruta de clases.
    • La fábrica de configuración de propiedades buscará log4j2.properties en la ruta de clases.
    • La fábrica de configuración YAML buscará log4j2.yml o log4j2.yaml en la ruta de clases.
    • La fábrica de configuración JSON buscará log4j2.jsn o log4j2.json en la ruta de clases.
    • La fábrica de configuración XML buscará log4j2.xml en la ruta de clases.
    • Si no se proporcionó ningún archivo de configuración, la DefaultConfiguration tomará su lugar y eso lo llevará a un conjunto de comportamientos predeterminados:
      • Se usará el registrador raíz.
      • El nivel del registrador raíz se establecerá en ERROR.
      • El registrador raíz propagará los mensajes de registro en la consola.
      • Se establece PatternLayout como %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n

Usar un archivo de configuración de log4j2 hace que la configuración de log4j2 sea muy simple, pero veamos cómo podemos configurarlo programáticamente. Esto se trata todo sobre el uso de ConfigurationFactory.

package com.journaldev;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.xml.XmlConfigurationFactory;
import org.apache.logging.log4j.core.layout.PatternLayout;
public class App
{
    public static void main( String[] args ) throws FileNotFoundException, IOException {
 
    	// Obtén una instancia de la fábrica de configuraciones; tus opciones son ConfigurationFactory predeterminada, XMLConfigurationFactory,
    	// YamlConfigurationFactory y JsonConfigurationFactory
    	ConfigurationFactory factory =  XmlConfigurationFactory.getInstance();
 
    	// Localiza la fuente de esta configuración, el archivo ubicado es un archivo ficticio que contiene solo una etiqueta de configuración vacía
    	ConfigurationSource configurationSource = new ConfigurationSource(new FileInputStream(new File("C:/dummyConfiguration.xml")));
 
    	// Obtiene una referencia de la configuración
    	Configuration configuration = factory.getConfiguration(configurationSource);
 
    	// Crea un apéndice de consola predeterminado
    	ConsoleAppender appender = ConsoleAppender.createDefaultAppenderForLayout(PatternLayout.createDefaultLayout());
 
    	// Agrega el apéndice de consola a la configuración
    	configuration.addAppender(appender);
 
    	// Crea loggerConfig
    	LoggerConfig loggerConfig = new LoggerConfig("com",Level.FATAL,false);
 
    	// Agrega el apéndice
    	loggerConfig.addAppender(appender,null,null);
 
    	// Agrega el logger y lo asocia con la instancia de loggerConfig
    	configuration.addLogger("com", loggerConfig);
 
    	// Obtiene una instancia de contexto
    	LoggerContext context = new LoggerContext("JournalDevLoggerContext");
 
    	// Inicia el sistema de registro
    	context.start(configuration);
 
    	// Obtiene una referencia para el logger
    	Logger logger = context.getLogger("com");
 
    	// LogEvent de mensaje DEBUG
    	logger.log(Level.FATAL, "Logger Name :: "+logger.getName()+" :: Passed Message ::");
 
    	// LogEvent de mensaje de error para el Logger configurado como FATAL
    	logger.log(Level.ERROR, "Logger Name :: "+logger.getName()+" :: Not Passed Message ::");
 
    	// LogEvent de mensaje de ERROR que sería manejado por Root
    	logger.getParent().log(Level.ERROR, "Root Logger :: Passed Message As Root Is Configured For ERROR Level messages");
    }
}
  • Puedes usar cualquiera de las ConfigurationFactory proporcionadas por Log4j2 o usar la predeterminada. Hemos utilizado XMLConfigurationFactory para obtener una instancia de ConfigurationFactory.
  • La fábrica te proporcionará una instancia de la referencia de Configuration requerida al pasar el archivo de configuración correspondiente.
  • La instancia de Configuration se utilizará junto con LoggerContext para iniciar el sistema de registro.
  • A console Appender has been configured and added into configuration instance with default layout. This Appender would print out messages into your console.
  • Se ha creado una instancia de LoggerConfig con el nombre proporcionado, LEVEL y sin filtro utilizado. El Apéndice creado se asignará a esta instancia de LoggerConfig.
  • La instancia de LoggerConfig se agregó a la instancia de configuración.
  • A new instance of LoggerContext is created with defined name.
  • La instancia de configuración ha sido pasada para la instancia de LoggerContext e invocada start en esta última.
  • A logger instance has been acquired from LoggerContext. This logger instance will be used to fire set of Log events.
  • La instancia de Logger ha lanzado tres eventos que se explicarán en la sección Niveles de Log4j2.
  • El logger com se ha configurado para imprimir mensajes cuyos niveles son FATAL.
  • Por defecto, el logger Root está configurado para imprimir mensajes cuyo nivel es ERROR.
  • Los mensajes de ERROR no se registrarán en el logger ‘com’ porque su nivel es FATAL.

La misma configuración se puede hacer utilizando YAML, JSON o un archivo de propiedades. Sin embargo, la configuración del archivo de propiedades de log4j2 es diferente del archivo de propiedades de log4j, así que asegúrate de no intentar usar la configuración del archivo de propiedades de log4j con log4j2. Esto generará el siguiente error;

ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.

Al procesar el código anterior, se obtendrá la siguiente salida:

Logger Name :: com :: Passed Message ::
00:01:27.705 [main] ERROR - Root Logger:: Passed Message As Root Is Configured For ERROR Level messages

La primera línea de registros es del logger com y la segunda es del Root Logger. El mensaje de error del logger com no se imprime porque su nivel es Fatal.

Niveles de Log4j2

Puedes ver en los ejemplos de código anteriores que cada vez que definimos un LoggerConfig, también proporcionamos el nivel de registro. Por defecto, el registro de log4j2 es aditivo. Esto significa que todos los loggers padres también se utilizarán cuando se utilice un logger específico. La imagen siguiente aclara esta situación. Y aquí hay puntos de aclaración para ello:

  • Como hemos mencionado antes, cada logger está asociado con una instancia de LoggerConfig. Este LoggerConfig ha sido definido en el ámbito de configuración.
  • El nivel de registro puede determinarse en el ámbito de LoggerConfig.
  • Puedes obtener el logger por su nombre, paquete padre o señalando directamente el Root Logger.
  • El Root Logger es el nodo de nivel superior para cada jerarquía de LoggerConfig.
  • Una vez que obtengas el logger com.journaldev e inicies un logEvent para el registro, el loggerConfig (net.journaldev) registrará el mensaje y el mensaje se propagará también hacia arriba en la jerarquía sin respetar los niveles de registro de los padres. Así que el evento de registro se propagará a los loggers com y Root y también registrarán el mensaje respectivamente según los niveles definidos.
  • Una vez que obtengas el logger com e inicies un logEvent para el registro, el loggerConfig (com) registrará el mensaje y el mensaje se propagará también hacia arriba en la jerarquía sin respetar los niveles de registro de los padres. Es decir, el Root logger propagará el evento de registro y también registrará el mensaje.
  • El mismo caso se aplica para la jerarquía net.journaldev.
  • Las próximas secciones agregarán más aclaraciones para el concepto aditivo.
  • Existe la posibilidad de que el padre ignore el mensaje utilizando el concepto de Filtro o configurando el indicador aditivo como falso, por lo que los eventos de registro no se propagarán a los padres.
  • Existe la posibilidad de que el registrador ignore el mensaje si el nivel de configuración del registrador respectivo es MAYOR QUE el nivel de eventos de registro.

Ahora, veamos el ejemplo asociado con el concepto de aditividad explicado anteriormente:

import net.NetApp;
import net.journaldev.NetJournalDevApp;
import com.ComApp;
import com.journaldev.ComJournalDevApp;
public class Main {
	public static void main(String [] args){
		new ComApp();
		new ComJournalDevApp();
		new NetApp();
		new NetJournalDevApp();
	}
}
package com.journaldev;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class ComJournalDevApp {
	public ComJournalDevApp(){
		Logger logger = LogManager.getLogger(ComJournalDevApp.class);
		logger.trace("COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::");
	}
}
package net;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class NetApp {
	public NetApp(){
		Logger logger = LogManager.getLogger(NetApp.class);
		logger.error("NET :: LEVEL :: NetApp ERROR Message ::");
	}
}
package net.journaldev;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class NetJournalDevApp {
	public NetJournalDevApp(){
		Logger logger = LogManager.getLogger(NetJournalDevApp.class);
		logger.error("NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::");
	}
}

Mientras que el archivo de configuración de log4j2 se ve así:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>

Si ejecutas la clase Principal encontrarás los siguientes resultados:

10:34:47.168 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
10:34:47.168 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
10:34:47.170 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
10:34:47.170 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
10:34:47.170 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
10:34:47.171 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
10:34:47.171 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
10:34:47.171 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
10:34:47.171 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
10:34:47.171 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

A continuación se muestra una explicación detallada del código anterior:

  • El archivo de configuración contiene cinco instancias de loggerConfig definidas y son Root, com, com.journaldev, net y net.journaldev. Al igual que la Jerarquía de Logger mostrada arriba.
  • El nivel de Root está configurado para ser ERROR y ese es en realidad el valor predeterminado.
  • Los niveles de com y com.journaldev están configurados para ser TRACE.
  • Los niveles de net y net.journaldev están configurados para ser ERROR.
  • Puedes notar que los mensajes de los registradores ComAPP y ComJournalDevApp se han mostrado dos y tres veces respectivamente. Estos mensajes se muestran según la Jerarquía de Logger para ComApp y ComJournalDevApp donde se encuentran en los paquetes com y com.journalDev respectivamente. Tenemos un caso similar con las clases NetApp y NetJournalDevApp.
  • Los padres se propagan ya que el indicador aditivo está configurado como verdadero por defecto.

El Espacio de Registro tiene en cuenta los Niveles de eventos de registro y el nivel de loggerConfig además de la Jerarquía del Registrador.

Entonces, ¿qué pasaría si cambiáramos el LoggerConfig para com a INFO y dejáramos todo el programa como está?

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="INFO">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>

Entonces, el resultado sería como sigue:

11:08:10.305 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
11:08:10.305 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
11:08:10.305 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
11:08:10.307 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
11:08:10.307 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
11:08:10.308 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
11:08:10.308 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
11:08:10.308 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
  • Seguramente notarás que el evento de registro de ComAPP ha sido ignorado y eso se debe al nivel definido de loggerConfig para el paquete com. El nivel INFO (400) es menor que el nivel del evento de registro, que aquí es TRACE(600). Entonces, el mensaje de ComApp ya no se mostrará y para que se muestre, necesitas modificar el nivel de LoggerConfig para com a TRACE(600) o ALL(Integer.MAX_VALUE).

Para asegurarte de que los eventos de registro se hayan mostrado, el Nivel de LoggerConfig debe ser mayor o igual al nivel del evento de registro.

La tabla a continuación te muestra los Niveles de log4j2 y el peso de cada uno de ellos:

LEVEL Weight
OFF 0
FATAL 100
ERROR 200
WARN 300
INFO 400
DEBUG 500
TRACE 600
ALL Integer.MAX_VALUE

Por supuesto, la tabla anterior aclara mucho más que las palabras y te da la causa principal de por qué el evento de registro TRACE no se muestra mientras que el nivel de LoggerConfig es INFO.

Nota que la propagación de eventos de registro hacia arriba en la jerarquía del registrador está más allá de este cálculo y ignora los niveles.

Pero, ¿qué sucede si eliminamos LoggerConfig de com.journaldev de la configuración y agregamos uno nuevo para com.journaldev.logging para que el archivo de configuración se vea así:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev.logging" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>

Es posible que encuentres la figura siguiente más conveniente para entender lo que ha ocurrido en la configuración de log4j2 mencionada anteriormente. Aquí tienes algunas aclaraciones sobre la figura mostrada anteriormente y cómo puede afectar el comportamiento de los eventos de registro:

  • Cuando los eventos de registro son lanzados por un Logger llamado com.journaldev.logging, el LoggerConfig asociado con ese nombre (es decir, com.journaldev.logging) ha sido utilizado para manejarlo e imprimir el mensaje.
  • Dado que el atributo aditivo de LoggerConfig com.journaldev.logging está establecido por defecto en true, el evento de registro ha sido propagado al padre, que en este caso se refiere a com.journaldev.
  • Dado que LoggerConfig com.journaldev no está definido en la configuración, no sucede ninguna acción y el evento de registro será propagado hasta las instancias de LoggerConfig de com y luego de Root.
  • Com & Root recibirán el evento de registro e imprimirán independientemente del nivel con el que se envíe.

Como resultado de los puntos mencionados, verías las siguientes salidas:

14:08:37.634 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:08:37.634 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:08:37.636 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:08:37.636 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:08:37.637 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:08:37.637 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:08:37.637 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:08:37.638 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:08:37.638 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:08:37.640 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:08:37.640 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:08:37.640 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

Y puedes notar lo siguiente:

  • El evento de registro en el paquete com se muestra dos veces. Una para com y otra para Root.
  • El evento de registro en com.journaldev se ha mostrado dos veces. Una vez para com y la segunda para Root. Aunque fue tres veces antes, pero por ahora el LoggerConfig de com.journaldev está ausente y por lo tanto puede que no haya ocurrido ningún registro en el paquete com.journaldev y el evento se propagaría para com y Root.
  • El evento de registro en com.journaldev.logging se ha mostrado tres veces, una vez para el paquete com.journaldev.logging, la segunda para com y la tercera para Root. Según la propagación de la jerarquía de loggers, debería mostrarse cuatro veces, pero debido a la ausencia de LoggerConfig de com.journaldev, se muestra tres veces.

En caso de que hayas definido una instancia de LoggerConfig de com.journaldev sin especificar un Nivel, heredará el Nivel de su padre.

Pero ¿qué pasa si has definido LoggerConfig de com.journaldev en tu archivo de configuración y olvidaste especificar el nivel de LoggerConfig? Afortunadamente, el concepto de Jerarquía de Loggers te salvará aquí y com.journaldev heredaría su valor de nivel de su padre. A continuación se muestra un archivo de configuración de ejemplo seguido de la tabla para el nivel de registro de cada configuración de logger.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev.logging" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>
Logger Name Assigned LoggerConfig LoggerConfig Level Logger Level
Root Root ERROR ERROR
com com TRACE TRACE
com.journaldev com TRACE TRACE
com.journaldev.logging com.journaldev.logging TRACE TRACE
  • El paquete com.journaldev.logging ya está asociado con un LoggerConfig con nivel de registro TRACE.
  • El paquete com.journaldev ya está asociado con un LoggerConfig sin nivel de registro especificado, por lo que heredaría el Nivel de Registro de su Padre y seguramente el valor sería TRACE para el paquete com.
  • El paquete com ya está asociado con un LoggerConfig con nivel de registro TRACE.
  • Por defecto, Root tiene ERROR como nivel de registro.
  • En caso de que el paquete com no esté declarado, LoggerConfig de com.journaldev heredará el nivel de registro de Root.

A continuación se muestra el resultado de la ejecución mientras com.journaldev hereda el nivel de registro de com:

14:41:37.419 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:41:37.419 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:41:37.421 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:41:37.421 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:41:37.421 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.423 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:41:37.423 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:41:37.423 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:41:37.423 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:41:37.423 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

Y a continuación se mostrará el resultado si eliminas la declaración de LoggerConfig para el paquete com:

14:43:28.809 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:43:28.809 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:43:28.809 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:43:28.811 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:43:28.811 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:43:28.812 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:43:28.812 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:43:28.812 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

Podrás notar que no se han registrado mensajes para com y com.journaldev, a continuación se detallan las razones.

  • La eliminación de LoggerConfig asociado con el paquete com hará que todos los eventos de registro mencionados en ese paquete sean ignorados.
  • Dado que no se ha definido LoggerConfig para el paquete com en la configuración, el LoggerConfig asociado con com.journaldev heredará el nivel de registro de su padre. Como Com no está definido, y la jerarquía de Logger ha alcanzado la parte superior y ahora se está refiriendo a Root. El nivel de registro raíz es ERROR(200) y el nivel de evento de registro en com.journaldev es TRACE(600) – Ver ComJournalDevApp – y según la ecuación previamente definida, el nivel de LoggerConfig debería ser mayor o igual al evento de registro y eso es falso, por lo que no se mostrarán mensajes aquí para com.journaldev.

Por último, pero no menos importante, la siguiente tabla muestra todos los posibles escenarios de registro que puedes enfrentar al usar el sistema de registro:

X (N/A) LoggerConfig Level OFF(0) FATAL(100) ERROR(200) WARN(300) INFO(400) DEBUG(500) TRACE(600) ALL(MAX)
Event Level X X X X X X X X X
OFF(0) X YES NO NO NO NO NO NO NO
FATAL(100) X NO YES YES YES YES YES YES YES
ERROR(200) X NO NO YES YES YES YES YES YES
WARN(300) X NO NO NO YES YES YES YES YES
INFO(400) X NO NO NO NO YES YES YES YES
DEBUG(500) X NO NO NO NO NO YES YES YES
TRACE(600) X NO NO NO NO NO NO YES YES
ALL(MAX) X NO NO NO NO NO NO NO YES
  • No hay un método directo que se pueda usar para lanzar eventos de registro OFF/ALL.
  • Principalmente, para lanzar eventos de registro OFF/ALL puedes usar logger.log(Level.OFF, “Msg”) o logger.log(Level.ALL, “Msg”), respectivamente.
  • El método de registro es responsable de manejar el evento de registro según la ecuación mencionada.

La ecuación de manejo dice: Si el nivel de LoggerConfig es mayor o igual al nivel de evento de registro, el evento se aceptará para su procesamiento posterior.

El evento de registro sería aceptado para su procesamiento posterior, esto es muy importante porque tienes la capacidad de evitar que algún evento sea manejado incluso si es aceptado utilizando Filtros de Log4j2. Puedes establecer la propiedad additive en falso para evitar la propagación del evento de registro a los registradores padres. A continuación, se muestra el mismo ejemplo que viste antes pero esta vez con un atributo de additivity, para que puedas notar la diferencia.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="TRACE" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev.logging" level="TRACE" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>

Y el resultado de la ejecución sería como sigue:

17:55:30.558 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
17:55:30.560 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
17:55:30.561 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
17:55:30.561 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
17:55:30.562 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

Y puedes notar que no hay propagación de eventos de registro a sus registradores padres.

Búsquedas de Log4j2

Idealmente, puedes definir búsquedas como una forma en la que puedes pasar valores para tu archivo de configuración de registro. Log4j2 te proporciona un conjunto diferente de Búsquedas que pueden ser utilizadas independientemente para establecer valores desde diferentes contextos:

  • Búsqueda de Mapa de Contexto
  • Búsqueda de Fecha
  • Búsqueda de Entorno
  • Búsqueda de Java
  • Búsqueda de JNDI
  • Búsqueda de Argumento de Entrada JVM (JMX)
  • Búsqueda de Argumentos Principales
  • Búsqueda de Mapa
  • Búsqueda de Datos Estructurados
  • Búsqueda de Propiedades del Sistema
  • Búsqueda Web

Puede consultar la documentación de Log4j2 para obtener más detalles sobre cada tipo de búsqueda, pero veamos aquí algunos ejemplos para cubrir los conceptos básicos de la Búsqueda de Log4j2. La Búsqueda de Entorno representa la forma en que puede pasar un valor de entorno (ya sea a través de Linux etc/profile, el entorno del sistema Windows o scripts de inicio para la aplicación). Como la mayoría de nosotros sabemos, tenemos la capacidad de definir un conjunto de valores ambientales para que la aplicación los use. Veamos las formas más comunes de definir sus variables ambientales.

  1. Defina la variable de entorno utilizando la facilidad de entorno de Windows:
    • Haga clic derecho en el ícono de su computadora y seleccione propiedades. Debería mostrarse el panel de control.
    • Haga clic en Configuración avanzada del sistema y luego abra la ventana de Variables de entorno.
    • En la sección Variables de sistema, defina la variable JournalDevVar con el valor JournalDev.
    • Actualice PatternLayout dentro de su log4j2.xml para incluir su variable recién agregada.

  1. Define sus variables de entorno utilizando la facilidad de script de inicio.
    • En lugar de usar el script predeterminado normal, puede utilizar la facilidad de script en ejecución de Eclipse IDE, haga clic en su menú Ejecutar y elija Configuración de Ejecución.
    • Navegue hasta la pestaña Entorno y defina su variable allí.

Mire ahora el archivo log4j2.xml modificado y observe el uso de variables de entorno.

<Console name="Console" target="SYSTEM_OUT">
    <PatternLayout pattern="%d{HH:mm:ss.SSS} $${env:JournalDevVar} $${env:JournalDevSecondVar} [%t] %-5level %logger{36} - %msg%n"/>
</Console>

Y el resultado de la ejecución se vería así:

23:57:02.511 JournalDev www.journaldev.com [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
23:57:02.517 JournalDev www.journaldev.com [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
23:57:02.520 JournalDev www.journaldev.com [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
23:57:02.523 JournalDev www.journaldev.com [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
23:57:02.527 JournalDev www.journaldev.com [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

Pero puede enfrentar un pequeño problema aquí, especialmente cuando está definiendo las variables de entorno de un sistema operativo y es la caché de Eclipse. Idealmente, Eclipse ha almacenado en caché todas las variables del sistema cuando se ejecuta y puede encontrarlas todas bajo Ejecutar – Configuración de ejecución – Pestaña Entorno – Haga clic en el botón Seleccionar. Por lo tanto, puede confundirse cuando las haya definido pero la aplicación no las reconozca. Incluso si reinicia Eclipse, no obtendrá la solución y para resolverlo, debe ejecutar eclipse.exe -clean en su instalación de Eclipse. Para asegurarse de que sus variables de entorno estén definidas correctamente y su sistema las encuentre fácilmente, puede utilizar el tipo de complemento de correspondencia que proporciona la API de Log4j2. Cree una instancia de EnvironmentLookup y pídale que busque una variable específica y, si está definida, las encontrará fácilmente.

EnvironmentLookup lookup = new EnvironmentLookup();
LogManager.getRootLogger().error(lookup.lookup("JournalDevSecondVar"));

Apéndices de Log4j2

Viste anteriormente cómo puedes usar Búsquedas para inyectar variables en tu archivo de configuración. Sin embargo, es posible que desees modificar el medio por el cual pasan tus mensajes. En lugar de utilizar la consola directamente, es posible que prefieras utilizar un archivo o un repositorio de base de datos para asegurarte de que tus mensajes se conserven permanentemente. Log4j2 ha proporcionado muchos Appenders, y puedes consultar la documentación de log4j2 para obtener más detalles sobre los Appenders. De manera breve, a continuación se muestra la lista de todos los Appenders de Log4j2.

  1. ConsoleAppender
  2. AsyncAppender
  3. FailoverAppender
  4. FileAppender
  5. FlumeAppender
  6. JDBCAppender
  7. JMSAppender
  8. JPAAppender
  9. MemoryMappedFileAppender
  10. NoSQLAppender
  11. OutputStreamAppender
  12. RandomAccessFileAppender
  13. RewriteAppender
  14. RollingFileAppender
  15. RollingRandomAccessFileAppender
  16. RoutingAppender
  17. SMTPAppender
  18. SocketAppender
  19. SyslogAppender

Los medios más utilizados para registrar eventos son la consola, el archivo y la base de datos. Mientras que el archivo podría guardar tus mensajes, la base de datos podría utilizarse para auditarlos. Con este propósito, esta sección se centrará en cómo se puede utilizar de manera eficiente el JDBCAppender.

JDBCAppender

El objetivo principal de JDBCAppender es escribir eventos de registro en una tabla relacional a través de conexiones JDBC. No dedicaremos mucho tiempo a explicar cómo puede optimizar sus grupos de conexiones, ya que este tutorial no está destinado a este propósito. Pero seguramente obtendrá un ejemplo completamente funcional que ayuda a escribir sus eventos de registro en la base de datos. Antes de que podamos continuar, veamos todos los parámetros necesarios y una descripción de cada uno para configurar JDBCAppender correctamente.

Parameter Name Type Description
Name String Required, The name of the Appender
ignoreExceptions boolean Default value is set to true, making exceptions thrown to be logged also and then ignored. False value means the exception will be propagated for the caller.
filter Filter The filter that should be used to make a decision whether the log events are going to be handled by this Appender or not.
bufferSize int Default value is zero, indicating there’s no buffering have been done upon log events. Value greater than 0 would lead the Appender to buffer log events and then flush them once the buffer reaches the limit specified.
connectionSource ConnectionSource Required, the connections source from which the database connections should be retrieved.
tableName String Required, the name of the Table on which your log events should be persisted.
columnConfigs ColumnConfig[] Required, additional information may be set upon those used columns and how the data should be persisted on each of them. This can be handled with multiple <Column> elements.
Parameter Name Type Description
jndiName String Required, full prefixed JNDI name that the javax.sql.Datasource is bound to.
Parameter Name Type Description
class String Requird, The fully qualified name for a class containg a static factory method for obtaining JDBC connections.
method boolean Required, The name of the static factory method for obtaining JDBC connections.
Parameter Name Type Description
name String Required, the name of the database column
pattern String Ability to specify any legal pattern that Log event would be formatted with
literal String Ability to specify literal value in this column (i.e. SEQ.NEXTVAL)
isEventTimestamp boolean Indicating whether the event would consider Timestamp
isUnicode boolean For unicode purpose as you may refer for Log4j2 documentation for further details
isClob boolean For storing character large object, you may refer for Log4j2 documentation for further details.

Dado que está obligado a usar JNDI, nuestro ejemplo configuraría un origen de datos de conexión para la base de datos Oracle y Apache Tomcat 7.

  • Si no ha instalado la base de datos Oracle en su entorno, se agradece si puede hacerlo. Si no está muy familiarizado con Oracle, le recomiendo instalar su Edición Express.
  • Instale Apache Tomcat 7 en su entorno.
  • Cree un proyecto Maven WebApp en su Eclipse.

  • Asegúrese de que su proyecto se haya creado correctamente y si nota algún error en el pom, asegúrese de corregirlos.
  • Agregue las dependencias de Log4j2.
<dependency>
   <groupId>org.apache.logging.log4j</groupId>
   <artifactId>log4j-api</artifactId>
   <version>2.2</version>
</dependency>
<dependency>
   <groupId>org.apache.logging.log4j</groupId>
   <artifactId>log4j-core</artifactId>
   <version>2.2</version>
</dependency>
  • Configure su contexto para incluir una declaración de origen de datos MySQL. Según la documentación de Apache, este archivo debería estar dentro de la carpeta META-INF de su Aplicación Web.

<Context path="/JournalDevWebLogging"
	privileged="true" antiResourceLocking="false" antiJARLocking="false">
	<Resource name="jdbc/JournalDevDB" auth="Container"
			factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
			type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000"
			username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
			url="jdbc:mysql://localhost:3306/journaldev" />
</Context>
  • Configure su base de datos y cree su Tabla de Registro.

CREATE TABLE `logging` (
  `EVENT_ID` int(11) NOT NULL AUTO_INCREMENT,
  `EVENT_DATE` datetime DEFAULT NULL,
  `LEVEL` varchar(45) DEFAULT NULL,
  `LOGGER` varchar(45) DEFAULT NULL,
  `MSG` varchar(45) DEFAULT NULL,
  `THROWABLE` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`EVENT_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
  • Configura tu log4j2.xml para que se vea como abajo:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
	<Appenders>
		<Console name="Console" target="SYSTEM_OUT">
			<PatternLayout
				pattern="%d{HH:mm:ss.SSS} $${env:JournalDevVar} $${env:JournalDevSecondVar} [%t] %-5level %logger{36} - %msg%n" />
		</Console>
		<JDBC name="databaseAppender" tableName="journaldev.logging">
			<DataSource jndiName="java:/comp/env/jdbc/JournalDevDB" />
			<Column name="EVENT_DATE" isEventTimestamp="true" />
			<Column name="LEVEL" pattern="%level" />
			<Column name="LOGGER" pattern="%logger" />
			<Column name="MSG" pattern="%message" />
			<Column name="THROWABLE" pattern="%ex{full}" />
		</JDBC>
	</Appenders>
	<Loggers>
		<Root level="ERROR">
			<AppenderRef ref="Console" />
		</Root>
		<logger name="com" level="TRACE" additivity="false">
			<AppenderRef ref="databaseAppender" />
		</logger>
		<logger name="com.journaldev" additivity="false">
			<AppenderRef ref="databaseAppender" />
		</logger>
	</Loggers>
</Configuration>
  • Crea cualquier recurso web que te permita obtener una referencia para un registrador y luego registrar un evento.
package com.journaldev;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class JournalDevServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
			Logger logger = LogManager.getLogger(JournalDevServlet.class);
			logger.trace("JournalDev Database Logging Message !");
	}
}
  • Opcionalmente puedes configurar un ServletContextListener que asegure que la inicialización del origen de datos se realice correctamente.
package com.journaldev;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.logging.log4j.LogManager;
public class JournalDevServletContextListener implements ServletContextListener{
	private InitialContext context = null;
	public void contextDestroyed(ServletContextEvent event) {
	}
	public void contextInitialized(ServletContextEvent event) {
		try {
			// Obtén el contexto inicial
			context = new InitialContext();
			// Obtiene una referencia para el subcontexto env
			Context envContext = (Context)context.lookup("java:comp/env");
			// Obtiene una referencia para el subcontexto jdbc y luego localiza el origen de datos definido
			LogManager.getRootLogger().error(((Context)envContext.lookup("jdbc")).lookup("JournalDevDB"));
		} catch (NamingException e) {
			LogManager.getRootLogger().error(e);
		}
	}
}
  • Define tu Servlet dentro de tu archivo web.xml.
  • Ejecuta la aplicación y accede al Servlet definido arriba. Verás los registros siguientes.
Mar 15, 2015 2:31:41 PM org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: C:\Program Files\Java\jdk1.6.0_26\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Program Files\Java\jdk1.6.0_26\jre\bin;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/bin/server;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/bin;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/lib/amd64;D:\OracleWebCenter\OracleWC\Oracle11g\app\oracle\product\11.2.0\server\bin;;C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\Program Files (x86)\Common Files\Microsoft Shared\Windows Live;D:\OracleDB\app\product\11.2.0\dbhome_1\bin;org.C:\Program Files (x86)\Common Files\NetSarang;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x86;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x64;D:\SpringRoo\spring-roo-1.2.5.RELEASE\bin;D:\Ant\apache-ant-1.9.2\bin;C:\Python27;C:\Program Files\Java\jdk1.6.0_26\bin;D:\Maven\apache-maven-3.2.1/bin;D:\bower-master\bin;C:\Program Files (x86)\Git\cmd;C:\Program Files\nodejs\;C:\Program Files\Microsoft Windows Performance Toolkit\;D:\Grails\grails-2.4.0\bin;D:\Gradle\gradle-2.0\bin;C:\Program Files (x86)\Windows Live\Shared;C:\Program Files\TortoiseSVN\bin;D:\Strawberry\perl\bin;D:\Strawberry\perl\site\bin;D:\Strawberry\c\bin;C:\Users\mohammad.amr\AppData\Roaming\npm;D:\JournalDev\eclipse;;.
Mar 15, 2015 2:31:41 PM org.apache.tomcat.util.digester.SetPropertiesRule begin
WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.j2ee.server:JournalDevWebLogging' did not find a matching property.
Mar 15, 2015 2:31:41 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-bio-8080"]
Mar 15, 2015 2:31:41 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["ajp-bio-8009"]
Mar 15, 2015 2:31:41 PM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 1020 ms
Mar 15, 2015 2:31:41 PM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Catalina
Mar 15, 2015 2:31:41 PM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.35
14:31:43.847 [localhost-startStop-1] ERROR  - org.apache.tomcat.jdbc.pool.DataSource@10fd0a62{ConnectionPool[defaultAutoCommit=null; defaultReadOnly=null; defaultTransactionIsolation=-1; defaultCatalog=null; driverClassName=com.mysql.jdbc.Driver; maxActive=100; maxIdle=30; minIdle=10; initialSize=10; maxWait=10000; testOnBorrow=false; testOnReturn=false; timeBetweenEvictionRunsMillis=5000; numTestsPerEvictionRun=0; minEvictableIdleTimeMillis=60000; testWhileIdle=false; testOnConnect=false; password=root; url=jdbc:mysql://localhost:3306/journaldev; username=root; validationQuery=null; validatorClassName=null; validationInterval=30000; accessToUnderlyingConnectionAllowed=true; removeAbandoned=false; removeAbandonedTimeout=60; logAbandoned=false; connectionProperties=null; initSQL=null; jdbcInterceptors=null; jmxEnabled=true; fairQueue=true; useEquals=true; abandonWhenPercentageFull=0; maxAge=0; useLock=false; dataSource=null; dataSourceJNDI=null; suspectTimeout=0; alternateUsernameAllowed=false; commitOnReturn=false; rollbackOnReturn=false; useDisposableConnectionFacade=true; logValidationErrors=false; propagateInterruptState=false; }
Mar 15, 2015 2:31:43 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8080"]
Mar 15, 2015 2:31:43 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-bio-8009"]
Mar 15, 2015 2:31:43 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 1909 ms

Filtros Log4j2

Incluso si hay un candidato LoggerConfig para manejar el evento de registro, puedes configurarlo para denegar el paso de los eventos de registro a los Appenders de backend. Esto se puede hacer mediante un filtro de log4j2. Esta sección no tiene la intención de proporcionarte un tutorial invasivo, masivo y enorme sobre el uso de filtros en Log4j2, ya que necesitaría una gran cantidad de artículos que cubran cada uno de ellos. Pero aquí, verás cómo usar el filtro más simple para entender el concepto. Uno de los filtros más simples que puedes usar es BurstFilter, que te proporciona un mecanismo para controlar la velocidad a la que se procesan los LogEvents descartando silenciosamente los eventos después de que se haya alcanzado el límite máximo. Por ahora, puedes ver todos los detalles necesarios para usar BurstFilter a continuación.

Parameter Name Type Description
level String Level of messages to be filtered
rate float The average number of events per second to allow
maxBurst integer The maximum number of events that can occur before events are filtered for exceeding the average rate. The default is 10 times the rate.
onMatch String Action to take when filter matches. May be Accept, DENY or NEUTRAL. The default is NEUTRAL
onMismatch String Action to tale when filter doesn’t match. May be Accept, DENY or NEUTRAL. The default is NEUTRAL

Ahora, mira la ubicación de BurstFilter dentro de tu Appender de base de datos.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
	<Appenders>
		<Console name="Console" target="SYSTEM_OUT">
			<PatternLayout
				pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
		</Console>
		<JDBC name="databaseAppender" tableName="journaldev.logging">
			<DataSource jndiName="java:/comp/env/jdbc/JournalDevDB" />
			<BurstFilter level="TRACE" rate="20" maxBurst="2"/>
			<Column name="EVENT_DATE" isEventTimestamp="true" />
			<Column name="LEVEL" pattern="%level" />
			<Column name="LOGGER" pattern="%logger" />
			<Column name="MSG" pattern="%message" />
			<Column name="THROWABLE" pattern="%ex{full}" />
		</JDBC>
	</Appenders>
	<Loggers>
		<Root level="ERROR">
			<AppenderRef ref="Console" />
		</Root>
		<logger name="com" level="TRACE" additivity="false">
			<AppenderRef ref="databaseAppender" />
		</logger>
		<logger name="com.journaldev" additivity="false">
			<AppenderRef ref="databaseAppender" />
		</logger>
	</Loggers>
</Configuration>
  • El Añalizador de Base de Datos sí considera BurstFilter, mientras que el Añalizador de Consola no lo hace.
  • Al usar el registrador de Consola, se registrarán todos los eventos de registro, pero el Añalizador de Base de Datos no lo hará, ya que el BurstFilter denegará que algunos de ellos continúen.
  • Esta negación de LogEvents se logra incluso cuando los registradores utilizados son candidatos para manejar los LogEvents. Esto es muy razonable como se muestra en el JournalDevServlet a continuación.

package com.journaldev;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class JournalDevServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
		Logger logger = LogManager.getLogger(JournalDevServlet.class);
		for(int i = 0 ; i < 1000 ; i++){
			logger.trace("Index :: "+i+" :: JournalDev Database Logging Message !");
			LogManager.getRootLogger().error("Index :: "+i+" :: JournalDev Database Logging Message !");
		}
	}
}

Incluso si esas configuraciones de Logger son candidatas para manejar los eventos de registro lanzados allí, el Filtro ha impedido que algunos de ellos sean manejados y luego registrados. Puedes agregar esto al concepto de Espacio de Registro para entender completamente el concepto de registro.

Diseños de Log4j2

Debido a los diferentes Apendices que consumen Eventos de Registro y la naturaleza de cada uno de ellos, los diseños se crean para formar el Evento de Registro en el formato que satisfaga las necesidades de quien vaya a consumir el evento de registro. En las APIs de Log4j 1.x y Logback, la transformación del diseño de los Eventos de Registro era en una cadena de caracteres, mientras que los diseños de Log4j2 han considerado una forma diferente de transformación; y eso es mediante la transformación del Evento de Registro en un arreglo de bytes. Este nuevo tipo de transformación te obligaría a configurar el Charset para asegurar que el arreglo de bytes contenga los valores correctos. Se recomienda encarecidamente regresar al sitio oficial de Apache Log4j2 y ver más sobre los Diseños y los diferentes tipos que Log4j2 proporciona. En esta sección, consideraremos el Diseño más famoso que siempre es utilizado por la mayoría de nuestros desarrolladores y que seguramente has escuchado sobre él; es PatternLayout.

Diseño de Patrón de Log4j2

El diseño de patrones es un patrón configurable y flexible de cadena destinado a dar formato al LogEvent. Este tipo de formato depende del concepto de patrón de conversión. Esta sección te mostrará las características más importantes que proporciona el diseño de patrones. El patrón de conversión está relacionado con el patrón de conversión que printf en el lenguaje C proporciona. Generalmente, el patrón de conversión se compone de texto literal y expresiones de control de formato llamadas especificadores de conversión. La figura siguiente te muestra de qué partes se compone el patrón de conversión: Esta figura anterior es un intento de simplificar el Patrón de Conversión, pero seguramente es mejor que consultes la documentación de Apache Log4j2 para obtener más detalles sobre los Diseños y, específicamente, el Diseño de Patrones. Además, puedes consultar arriba para ver eventos de registro y ver en todo momento qué Patrón de Conversión se utiliza para dar formato a los mensajes.

¿Qué nivel de Log4j2 deberías usar?

La pregunta más importante que te puedes hacer es cuándo se debe usar un nivel específico de evento de registro. En el campo del desarrollo, es normal usar el evento de registro DEBUG, mientras que en producción deberíamos usar el nivel INFO o WARN. La siguiente tabla debería guiarte sobre qué nivel de log4j2 se debería usar en cada caso.

Log Event Level When It Should Be Used
OFF When no events will be logged
FATAL When a severe error will prevent the application from continuing
ERROR When an error in the application, possibly recoverable
WARN When an event that might possible lead to an error
INFO When an event for informational purposes
DEBUG When a general debugging event required
TRACE When a fine grained debug message, typically capturing the flow through the application
ALL When all events should be logged

Resumen del Tutorial de Log4j2

Log4j2 es una versión renovada del marco de registro de Apache. Log4j2 ha proporcionado un conjunto de nuevas características y mejoras de rendimiento desde Log4j1.x. Este tutorial de log4j2 tiene como objetivo ayudarte a comprenderlo todo en un solo lugar. Dado que algunos de estos conceptos no son tan fáciles de cubrir de una sola vez, hemos decidido concentrar nuestros esfuerzos en explicar el concepto y usar algunos ejemplos para una mayor clarificación. Los Apendices, Filtros, Diseños y Búsquedas están sujetos a esta regla. Algunos puntos importantes Para asegurarse de que pueda ejecutar la aplicación a continuación y evitar cualquier obstáculo, verifique lo siguiente:

  • Su IDE de Eclipse está habilitado para Maven.
  • Su Apache Tomcat tiene un archivo JAR mysql-connector dentro de la carpeta lib de su directorio principal de Apache.
  • Está familiarizado con el uso de Maven.

Descargar el Proyecto de Ejemplo de Apache Log4j 2

Eso es todo para el tutorial de log4j2, espero que se cubran la mayoría de los puntos importantes para comenzar a usar Log4j2 en su aplicación.

Source:
https://www.digitalocean.com/community/tutorials/log4j2-example-tutorial-configuration-levels-appenders