Ejemplo Log4j 2 en JAVA | Log4j 2 en Springboot | Configuración Log4j 2 | Log4j 2 in SpringBoot| Example Log4j 2 in SpringBoot | Configuring Log4j 2

Log4j versión 2.x en JAVA | Log4j versión 2.x en SpringBoot


Apache Log4j 2 o 2.x es una actualización muy importante de Log4j, la cual proporciona innumerables mejoras con respecto a las versiones anteriores, entre estas mejoras: Logback, manejo asíncrono, etc.


Objetivo


Configurar Log4j versión 2 o 2.x en proyectos Spring.


Requisitos:


  • Java 11 (Open)

  • Eclipse

  • SpringBoot 2.2.4.RELEASE

  • Maven


En Acción:

Para este ejemplo se debe contar con un proyecto en SpringBoot, el cual se pueda implementar o mejorar el uso de Log4j 2 o 2.x.


log4j2-spring.xml

El archivo de configuración para Log4j versión 2 se define de dos formas:
  • logj2.xml para proyectos sin Spring
  • log4j-spring.xml para proyectos que usen Spring
Para ambos archivos se mantiene la misma declaración de propiedades.

<?xml version="1.0" encoding="UTF-8"?>
<!--https://logging.apache.org/log4j/2.x/manual/configuration.html-->
<Configuration status="TRACE" monitorInterval="30">
    <!-- Definición de propiedades | property definition -->
<Properties>
<Property name="LOG_PATTERN">%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ} [%t] %-5level %logger{36} - %msg%n</Property>
<Property name="APP_LOG_ROOT">var/log/tomcat0</Property>
</Properties>
<Appenders>
<!-- Console Appender | Escritura de los en la consola-->
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="${LOG_PATTERN}" />
</Console>
<!-- File Appenders on need basis -->
<RollingFile name="frameworkLog"
    fileName="${APP_LOG_ROOT}/logs/app-framework.log"
filePattern="${APP_LOG_ROOT}/logs/$${date:yyyy-MM}/app-framework-%d{yyyy-MM-dd}-%i.log.gz">
<LevelRangeFilter minLevel="ERROR" maxLevel="ERROR" onMatch="ACCEPT"
onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="19500KB" />
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
<RollingFile name="debugLog"
fileName="${APP_LOG_ROOT}/logs/automatizador-debug.log"
filePattern="${APP_LOG_ROOT}/logs/$${date:yyyy-MM}/automatizador-debug-%d{yyyy-MM-dd}-%i.log.gz">
<LevelRangeFilter minLevel="DEBUG" maxLevel="DEBUG" onMatch="ACCEPT"
onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="19500KB" />
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
<RollingFile name="infoLog"
fileName="${APP_LOG_ROOT}/logs/automatizador-info.log"
filePattern="${APP_LOG_ROOT}/logs/$${date:yyyy-MM}/automatizador-info-%d{yyyy-MM-dd}-%i.log.gz" >
<LevelRangeFilter minLevel="INFO" maxLevel="INFO" onMatch="ACCEPT"
onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="19500KB" />
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
<RollingFile name="errorLog"
fileName="${APP_LOG_ROOT}/logs/automatizador-error.log"
filePattern="${APP_LOG_ROOT}/logs/$${date:yyyy-MM}/automatizador-error-%d{yyyy-MM-dd}-%i.log.gz" >
<LevelRangeFilter minLevel="ERROR" maxLevel="ERROR" onMatch="ACCEPT"
onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="19500KB" />
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
<RollingRandomAccessFile name="traceLogAsyncFile"
fileName="${APP_LOG_ROOT}/logs/automatizador-trace.log"
filePattern="${APP_LOG_ROOT}/logs/$${date:yyyy-MM}/automatizador-trace-%d{yyyy-MM-dd}-%i.log.gz" >
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="19500KB" />
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingRandomAccessFile>
<Async name="traceLogAsync">
<AppenderRef ref="traceLogAsyncFile"/>
</Async>
</Appenders>
<Loggers>
<Logger name="com.advanced.development" additivity="false"
level="trace">
<AppenderRef ref="traceLogAsync" />
<AppenderRef ref="debugLog" />
<AppenderRef ref="infoLog" />
<AppenderRef ref="errorLog" />
<AppenderRef ref="Console" />
</Logger>
<Logger name="org.springframework" additivity="false" level="error">
<AppenderRef ref="frameworkLog" />
<AppenderRef ref="Console"/>
</Logger>
<Root level="error">
<AppenderRef ref="errorLog"/>
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>


Properties: Se declaran todas las propiedades que se van a usar en la definición de la configuración de Log.

Para este caso se declaró LOG_PATTERN y APP_LOG_ROOT, la primera define el patrón que se va a imprimir en los logs a la hora de registrar los eventos(errors, warn, info, etc) y el segundo define la ubicación en la cual se van a almacenar los archivos Logs.

<!-- Definición de propiedades | property definition -->
<Properties>
<Property name="LOG_PATTERN">%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ} [%t] %-5level %logger{36} - %msg%n</Property>
<Property name="APP_LOG_ROOT">var/log/tomcat0</Property>
</Properties>


Console: Se define la configuración para la escritura de eventos en la consola del IDE, terminal, etc.

<!-- Console Appender | Escritura de los en la consola-->
<Console name="Console" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="${LOG_PATTERN}" />
</Console>


RollingFile: Permite definir la configuración para cada uno de los archivos logs que se requieran. En este ejemplo de definió: debubLog, infoLog, warnLog, errorLog y frameworkLog.

frameworkLog es usado solo para imprimir eventos de tipo error de los framework de terceros, por ejemplo: Spring.

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

<LevelRangeFilter minLevel="ERROR" maxLevel="ERROR" onMatch="ACCEPT"
    onMismatch="DENY"/>
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="19500KB" />
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingFile>


RollingRandomAccessFile: Permite definir la configuración para eventos asincronos. Esta propiedad mejora el rendimiento notablemente, y desde la experiencia se recomienda usar en los registros de tipo TRACE.

<RollingRandomAccessFile name="traceLogAsyncFile"
fileName="${APP_LOG_ROOT}/logs/automatizador-trace.log"
filePattern="${APP_LOG_ROOT}/logs/$${date:yyyy-MM}/automatizador-trace-%d{yyyy-MM-dd}-%i.log.gz" >
<PatternLayout pattern="${LOG_PATTERN}"/>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="19500KB" />
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingRandomAccessFile>


Async: Para usar el RollingRandomAccessFile se requiere de la propiedad Async, dado que esta se encarga de controlar y hacer referencia a la definición de configuración.

<Async name="traceLogAsync">
<AppenderRef ref="traceLogAsyncFile"/>
</Async>


Logger: Se declaran los Logger necesarios para el registro de eventos. Para este caso se crearon 2 Logger, uno para el registro de eventos (trace, debug, info, error, console) para el paquete "com.advanced.development"  y sus descendencias. El otro fue creado para registrar los eventos de los framework.

<Logger name="com.advanced.development" additivity="false"
level="trace">
<AppenderRef ref="traceLogAsync" />
<AppenderRef ref="debugLog" />
<AppenderRef ref="infoLog" />
<AppenderRef ref="errorLog" />
<AppenderRef ref="Console" />
</Logger>
<Logger name="org.springframework" additivity="false" level="error">
<AppenderRef ref="frameworkLog" />
<AppenderRef ref="Console"/>
</Logger>


Clase Logger: En todos mis años de experiencias y en todos los proyectos que he estado, me he dado cuenta que crear una clase Logger es fundamental para resolver muchos problemas y más si se trabaja con herramientas de Análisis de código como VERACODE y FORTIFY. Declarar una clase Logger permite un escalamiento ordenado y rápido. En el caso que se requiera migrar de una versión de Logger a otra, es solo realizar el ajuste en la clase y el proyecto no se ve afectado. Piensa a mediano y largo plazo.


package com.advanced.development.log4j2.services;

import java.io.File;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;

public class Logger {
private org.apache.logging.log4j.Logger logger;

private Logger(Class<? extends Object> clazz) {
this.logger = LogManager.getLogger(clazz);
}

private Logger(String clazz) {
this.logger = LogManager.getLogger(clazz);
}

public static Logger getLogger(Class<? extends Object> clazz) {
return new Logger(clazz);
}

public static Logger getLogger(String clazz) {
return new Logger(clazz);
}

public void info(Object message) {
this.logger.info(message);
}

public void debug(Object message) {
this.logger.debug(message);
}

public void debug(Object message, Throwable throwable) {
this.logger.debug(message, throwable);
}

public void error(Object message) {
this.logger.error(message);
}

public void error(Object message, Throwable throwable) {
this.logger.error(message, throwable);
}

public void warn(Object message) {
this.logger.warn(message);
}

public void warn(Object message, Throwable throwable) {
this.logger.warn(message, throwable);
}

public static void setConfigFile(String logConfigFile) {
File file = new File(logConfigFile);
LoggerContext context =
(org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
context.setConfigLocation(file.toURI());
}
}



Uso Logger: Al crear una clase intermedia que se encargue de registrar los eventos, usarla es literalmente igual que llamar directamente al Logger de Apache.


package com.advanced.development.log4j2;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.advanced.development.log4j2.services.Logger2;

@SpringBootApplication
@EnableAutoConfiguration
public class StartApplication implements CommandLineRunner {
private static final Logger2 LOGGER =
Logger2.getLogger(StartApplication.class);
public static void main(String[] args) {
SpringApplication.run(StartApplication.class, args);
}
@Override
public void run(String... args) {
LOGGER.info("StartApplication...");
}
}



Resultados:


Resultados obtenidos mediante el uso del Log4jk versión 2.x.


    Logs de salidas:
Consola del IDE:
Resultado de los LOGs:


  
 


Código fuentes:

Notas finales: -


No olvides compartir y dar +1

-

Próximos eventos:

* Habilitar https en GOlang
* Ejecutar código HTML estático en DOCKER
* Microservicios en Python
* Python+MongoDB: CRUD
* Python+MongoDB+GridFS: Almacenamiento de archivos
* Colas - Queue Python: Envío de mensajes
* Python+AWS+SNS: Envío de mensajes de textos.
* Python3: Creación de un Chatbot básico
* NodeJS+MongoDB: CRUD

El orden de los eventos puede cambiar

Comentarios

Entradas más populares de este blog

Python: Inyección de dependencias

GOlang con Docker | GOlang with Docker | GO con Docker | GO with Docker