java logging log4j log4j2

java - ¿Cómo personalizar log4j2 RollingFileAppender?



logging (2)

Esto se puede lograr con la configuración. Puede usar el encabezado del diseño del patrón para generar información. Esto se incluirá en cada reinversión.

<RollingFile name="RollingFile" fileName="logs/app.log" filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}.log.gz"> <!-- use built-in lookups for system info or system properties --> <PatternLayout header="${java:runtime} - ${java:vm} - ${java:os}"> <Pattern>%d %m%n</Pattern> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy /> </Policies> </RollingFile>

Utilizamos log4j 1.2.x para iniciar sesión en nuestro producto y estamos buscando migrar a log4j 2.x en un futuro próximo. Una de las funcionalidades que hemos implementado es registrar la información del sistema y otros parámetros importantes en cada nuevo archivo de registro que se genera. La forma en que implementamos en log4j 1.2.x es que hemos extendido la clase RollingFileAppender de log4j y hemos anulado el método rollOver() , a continuación se muestra el fragmento de parte de la implementación

@Override public void rollOver() { super.rollOver(); //We are not modifying it''s default functionality but as soon as rollOver happens we apply our logic // // Logic to log required system properties and important parameters. // }

Ahora, como queremos migrar a log4j2, estamos buscando una nueva solución para lograr la misma funcionalidad. Pero como veo el código fuente de log4j2, es muy diferente del código fuente anterior. La clase RollingFileAppender no contiene el método rollover() ya que se ha movido a RollingManagerhelper y también se ha establecido en private .

Desarrollar un nuevo paquete completo y extender / implementar algunas clases abstractas / auxiliares de log4j2 es una de las posibles soluciones para nosotros, pero eso requeriría mucha codificación / copia, ya que no modificamos lo que hace RollingFileAppender , sino que solo necesitamos una pequeña extensión. . ¿Hay una solución simple para ello?

ACTUALIZAR

Creé una búsqueda personalizada de acuerdo con la sugerencia en las respuestas y a continuación es cómo la creé;

@Plugin(name = "property", category = StrLookup.CATEGORY) public class CustomLookup extends AbstractLookup { private static AtomicLong aLong = new AtomicLong(0); @Override public String lookup(LogEvent event, String key) { if (aLong.getAndIncrement() == 0) { return "this was first call"; } if (key.equalsIgnoreCase("customKey")) { return getCustomHeader(); } else { return "non existing key"; } } private static String getCustomHeader() { // Implementation of custom header return "custom header string"; }}

Pero esto no funcionó como se mencionó; esto siempre imprime this was first call en el encabezado. También intenté poner breakoint en la primera condición if y lo que noté fue que solo se llama una vez. Entonces, lo que temo es que la clase customLookup solo se inicializa en el inicio cuando log4j2 está inicializando sus propiedades desde la configuración xml. No sé cómo podría implementar esta clase de búsqueda personalizada.

ACTUALIZACIÓN 2

Después de la implementación anterior, lo intenté de una manera un poco diferente, que es la siguiente;

private static AtomicLong aLong = new AtomicLong(0); @Override public String lookup(LogEvent event, String key) { return getCustomHeader(key); } private static String getCustomHeader(final String key) { if (aLong.getAndIncrement() == 0) { return "this was first call"; } if (key.equalsIgnoreCase("customKey")) { // Implementation for customKey return "This is custom header"; } else { return "non existing key"; } }

Pero esto también hace lo mismo. log4j2 crea los encabezados en mientras se inicializa desde su archivo de configuración xml y luego usa los encabezados de la memoria. El valor de return del método de lookup() anulada lookup() no se puede cambiar dinámicamente, ya que solo se llama durante la inicialización. Cualquier otra ayuda sería muy apreciada.


Una alternativa al uso de las búsquedas integradas es crear una búsqueda personalizada. Esto se puede lograr en unas pocas líneas de código con un complemento log4j2. Su búsqueda personalizada proporciona el valor exacto que desea mostrar en el encabezado del archivo en cada rollover.

El código del complemento se vería así:

package com.mycompany; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.plugins.Plugin; import org.apache.logging.log4j.core.lookup.AbstractLookup; import org.apache.logging.log4j.core.lookup.StrLookup; /** * Looks up keys from a class SomeClass which has access to all * information you want to provide in the log file header at rollover. */ @Plugin(name = "setu", category = StrLookup.CATEGORY) public class SetuLookup extends AbstractLookup { /** * Looks up the value of the specified key by invoking a * static method on SomeClass. * * @param event The current LogEvent (ignored by this StrLookup). * @param key the key to be looked up, may be null * @return The value of the specified key. */ @Override public String lookup(final LogEvent event, final String key) { return com.mycompany.SomeClass.getValue(key); } }

Luego, en su configuración, puede usar el encabezado del diseño del patrón para generar esto en cada rollover:

<RollingFile name="RollingFile" fileName="logs/app.log" filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}.log.gz"> <!-- use custom lookups to access arbitrary internal system info --> <PatternLayout header="${setu:key1} ${setu:key2}"> <Pattern>%d %m%n</Pattern> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy /> </Policies> </RollingFile>

El manual log4j2 tiene detalles sobre la construcción / implementación de complementos personalizados . Breve resumen:

La forma más fácil es construir tu jarra con Maven; esto hará que el procesador de anotaciones log4j2 produzca un archivo de índice binario en el archivo jar para que log4j2 pueda encontrar rápidamente su complemento.

La alternativa es especificar el nombre del paquete de su clase de complemento en el atributo de packages su configuración log4j2.xml:

<Configuration status="warn" packages="com.mycompany"> ...

ACTUALIZACIÓN: Tenga en cuenta que en su implementación de búsqueda puede ser tan creativo como sea necesario. Por ejemplo:

package com.mycompany; public class SomeClass { private static AtomicLong count = new AtomicLong(0); public static String getValue(final String key) { if (count.getAndIncrement() == 0) { // is this the first call? return ""; // don''t output a value at system startup } if ("FULL".equals(key)) { // returns info to shown on rollover, nicely formatted return fullyFormattedHeader(); } return singleValue(key); } .... }