Custom ThrowableRenderer no funciona log4j 1.x

Aug 27 2020

Estoy tratando de hacer que un throwableRenderer personalizado funcione con log4j 1.2.17.
Tenga en cuenta que no puedo actualizar a log4j2 en esta etapa, así que estoy buscando una solución 1.x.

Consulte, por ejemplo,
¿Cómo hacer que el appender log4j syslog escriba un seguimiento de pila en una línea?

Estoy tratando de hacer precisamente eso: hacer que el seguimiento de la pila se imprima en 1 línea. Probé 2 enfoques que pude encontrar en la web: usar un renderizador personalizado y usar Enhanced Pattern Layout. ¡Aún sin suerte!

Pero la clase WRThrowableRenderer(que es mi renderizador personalizado)
y su método doRendersimplemente no se llaman.
Todo esto está en una aplicación web que se ejecuta dentro de WildFly 8 (Java 8).

Probé al menos 10 cosas diferentes mientras probaba los dos enfoques, pero nada funciona.

¡¿Qué estoy haciendo mal?!

Además, ¿se supone que este renderizador afecta a todos los registradores y cambia su comportamiento cuando se registra una excepción? Creo que sí. Estoy preguntando esto porque tengo registradores de niños en este rootLogger. Y todos se registran a través de rootLogger en un solo archivo.

log4j.rootLogger=INFO, stdout

log4j.throwableRenderer=com.yb.common.logging.WRThrowableRenderer

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout
# log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%t] ###%c{20}:%L### - [[[%m]]]%n
# log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%t] ###%c{20}### [[[%m]]]%n %throwable{separator(|)}
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%t] ###%c{20}### [[[%m]]]%n
# log4j.appender.stdout.layout.ConversionPattern=%m%n

log4j.appender.stdout.threshold=INFO
log4j.appender.stdout.immediateFlush=true

Respuestas

bmaupin Nov 20 2020 at 17:42

Estoy tratando de hacer precisamente eso: hacer que el seguimiento de la pila se imprima en 1 línea. Probé 2 enfoques que pude encontrar en la web: usar un renderizador personalizado y usar Enhanced Pattern Layout.

Sin un ThrowableRenderer personalizado

Si desea que el seguimiento de la pila se realice todo en una línea sin utilizar una función personalizada ThrowableRenderer, lo mejor que podrá hacer es obtener la primera línea del seguimiento de la pila.

Por ejemplo, usando esta configuración:

log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%d] %-5p %m %throwable{short}%n

Generará este registro:

[2020-11-20 10:54:53,454] ERROR Test error message, with stack trace java.lang.IllegalArgumentException: Test exception message

Con un ThrowableRenderer personalizado

Si desea que se imprima todo el seguimiento de la pila en una línea, deberá utilizar un ThrowableRenderer personalizado.

  1. Cree el ThrowableRenderer personalizado, p. Ej.

    package org.example;
    
    import org.apache.log4j.DefaultThrowableRenderer;
    import org.apache.log4j.spi.ThrowableRenderer;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    
    public class CustomThrowableRenderer implements ThrowableRenderer {
        private final DefaultThrowableRenderer defaultRenderer = new DefaultThrowableRenderer();
    
        @Override
        public String[] doRender(Throwable throwable) {
            String[] defaultRepresentation = defaultRenderer.doRender(throwable);
            String[] newRepresentation = {String.join("|", Arrays.asList(defaultRepresentation))};
    
            return newRepresentation;
        }
    }
    
  2. Configure log4j1 para usar el ThrowableRenderer personalizado

    log4j.throwableRenderer=org.example.CustomThrowableRenderer
    

En este punto, la parte de seguimiento de pila del registro estará en una línea, aunque puede estar en una línea separada del resto del registro.

Por ejemplo, su configuración de arriba:

log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%t] ###%c{20}### [[[%m]]]%n
log4j.throwableRenderer=org.example.CustomThrowableRenderer

Generará dos líneas porque el seguimiento de la pila se coloca en su propia línea de forma predeterminada:

2020-11-20 11:45:04.706 ERROR [main] ###org.example.App### [[[Test error message, with stack trace]]]
java.lang.IllegalArgumentException: Test exception message|     at org.example.App.logErrorWithStackTrace(App.java:31)| at org.example.App.okayThatsEnough(App.java:25)|        at org.example.App.notLongEnough(App.java:21)|  at org.example.App.makeStackTraceLonger(App.java:17)|   at org.example.App.testLoggingWithStackTraces(App.java:13)|     at org.example.App.main(App.java:9)

Puede obtener el mensaje de error y el seguimiento de la pila en una línea usando %throwableen su patrón:

log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%t] ###%c{20}### [[[%m]]] %throwable%n

Sin embargo, se generará una línea en blanco después de:

2020-11-20 11:46:46.897 ERROR [main] ###org.example.App### [[[Test error message, with stack trace]]] java.lang.IllegalArgumentException: Test exception message|       at org.example.App.logErrorWithStackTrace(App.java:31)| at org.example.App.okayThatsEnough(App.java:25)|        at org.example.App.notLongEnough(App.java:21)|  at org.example.App.makeStackTraceLonger(App.java:17)|   at org.example.App.testLoggingWithStackTraces(App.java:13)|     at org.example.App.main(App.java:9)

Eso probablemente también podría arreglarse, pero podría requerir un appender personalizado.

Hice una pequeña aplicación de muestra que puedes usar como referencia: https://github.com/bmaupin/junkpile/tree/master/java/log4j1-custom-throwablerenderer