Configurar Log4j Loggers mediante programación

191

Estoy tratando de usar SLF4J (con log4jenlace) por primera vez.

Me gustaría configurar 3 Loggers con nombre diferentes que pueden ser devueltos por un LoggerFactory que registrará diferentes niveles y enviará los mensajes a diferentes apéndices:

  • Logger 1 "FileLogger" registra DEPURACIÓN y se agrega a DailyRollingFileAppender
  • Logger 2 "TracingLogger" registra TRACE + y se agrega a un JmsAppender
  • Logger 3 "ErrorLogger" registra ERROR + y se agrega a un archivo diferente JmsAppender

Además, los quiero configurados mediante programación (en Java, a diferencia de XML o un log4j.propertiesarchivo).

Me imagino que, normalmente, definiría estos Loggers en algún lugar de algún código de arranque, como un init()método. Sin embargo, debido a que quiero usar slf4j-log4j, estoy confundido acerca de dónde podría definir los registradores y ponerlos a disposición del classpath.

No creo que esto sea una violación del propósito subyacente de SLF4J (como fachada), porque mi código que usa la API SLF4J nunca sabrá que existen estos registradores. Mi código solo realiza llamadas normales a la API SLF4J, que luego las reenvía a los Log4j Loggers que encuentra en el classpath.

¿Pero cómo configuro esos Log4j Loggers en el classpath ... en Java?

IAmYourFaja
fuente
3
Para log4j 1.x use la respuesta aceptada a continuación para 2.x, consulte logging.apache.org/log4j/2.x/manual/customconfig.html
earcam

Respuestas:

279

Puede agregar / eliminar Appender mediante programación a Log4j:

  ConsoleAppender console = new ConsoleAppender(); //create appender
  //configure the appender
  String PATTERN = "%d [%p|%c|%C{1}] %m%n";
  console.setLayout(new PatternLayout(PATTERN)); 
  console.setThreshold(Level.FATAL);
  console.activateOptions();
  //add appender to any Logger (here is root)
  Logger.getRootLogger().addAppender(console);

  FileAppender fa = new FileAppender();
  fa.setName("FileLogger");
  fa.setFile("mylog.log");
  fa.setLayout(new PatternLayout("%d %-5p [%c{1}] %m%n"));
  fa.setThreshold(Level.DEBUG);
  fa.setAppend(true);
  fa.activateOptions();

  //add appender to any Logger (here is root)
  Logger.getRootLogger().addAppender(fa);
  //repeat with all other desired appenders

Te sugiero que lo pongas en un init () en algún lugar, donde estés seguro, de que esto se ejecutará antes que nada. Luego puede eliminar todos los apéndices existentes en el registrador raíz con

 Logger.getRootLogger().getLoggerRepository().resetConfiguration();

y comience agregando los suyos. Necesita log4j en el classpath, por supuesto, para que esto funcione.

Observación:
puede tomar cualquiera que Logger.getLogger(...)desee para agregar apéndices. Acabo de tomar el registrador raíz porque está en la parte inferior de todas las cosas y manejará todo lo que se pasa a través de otros anexos en otras categorías (a menos que se configure de otra manera configurando el indicador de aditividad).

Si necesita saber cómo funciona el registro y cómo se decide dónde se escriben los registros, lea este manual para obtener más información al respecto.
En breve:

  Logger fizz = LoggerFactory.getLogger("com.fizz")

le dará un registrador para la categoría "com.fizz".
Para el ejemplo anterior, esto significa que todo lo registrado con él se referirá a la consola y al archivo adjunto en el registrador raíz.
Si agrega un appender a Logger.getLogger ("com.fizz"). AddAppender (newAppender), entonces el inicio de sesión fizzserá manejado por alle los appenders del registrador raíz y el newAppender.
No crea registradores con la configuración, solo proporciona controladores para todas las categorías posibles en su sistema.

Oers
fuente
2
Gracias oers! Pregunta rápida: noté que está agregando los apéndices al registrador raíz. ¿Hay alguna razón para esto?
IAmYourFaja
Y, lo que es más importante, tendré que especificar qué Logger recuperar de LoggerFactory de SLF4J. ¿Es posible pedirle a SLF4J el logger raíz de log4j?
IAmYourFaja
3
@ AdamTannon Puedes tomar cualquier Logger.getLogger (...) que quieras. Acabo de tomar el registrador raíz porque está en la parte inferior de todas las cosas y manejará todo lo que se pasa a través de otros anexos en otras categorías (a menos que esté configurado de otra manera). Ver registrador de jerarquía
Oers
@ AdamTannon no puedes usar la fábrica sl4j para obtener el log4j root logger. SL4j es una fachada de tala. No obtendrá nada log4j específico de él.
Oers
2
oers - Agradezco sus maravillosos comentarios, pero simplemente no estoy conectando todos los puntos aquí. ¿Puede modificar su ejemplo para mostrar la adición de un nuevo registrador (no el registrador raíz) que, una vez agregado al sistema, estará disponible para cualquier otra clase que lo solicite? Por ejemplo, un registrador al que normalmente se accedería, por ejemplo, Logger fizz = LoggerFactory.getLogger("com.fizz");¡gracias!
IAmYourFaja
47

Parece que está intentando utilizar log4j desde "ambos extremos" (el consumidor final y el final de la configuración).

Si desea codificar contra la API slf4j pero determinar con anticipación (y mediante programación) la configuración de los Log4j Loggers que el classpath devolverá, absolutamente debe tener algún tipo de adaptación de registro que haga uso de la construcción perezosa.

public class YourLoggingWrapper {
    private static boolean loggingIsInitialized = false;

    public YourLoggingWrapper() {
        // ...blah
    }

    public static void debug(String debugMsg) {
        log(LogLevel.Debug, debugMsg);
    }

    // Same for all other log levels your want to handle.
    // You mentioned TRACE and ERROR.

    private static void log(LogLevel level, String logMsg) {
        if(!loggingIsInitialized)
            initLogging();

        org.slf4j.Logger slf4jLogger = org.slf4j.LoggerFactory.getLogger("DebugLogger");

        switch(level) {
        case: Debug:
            logger.debug(logMsg);
            break;
        default:
            // whatever
        }
    }

    // log4j logging is lazily constructed; it gets initialized
    // the first time the invoking app calls a log method
    private static void initLogging() {
        loggingIsInitialized = true;

        org.apache.log4j.Logger debugLogger = org.apache.log4j.LoggerFactory.getLogger("DebugLogger");

        // Now all the same configuration code that @oers suggested applies...
        // configure the logger, configure and add its appenders, etc.
        debugLogger.addAppender(someConfiguredFileAppender);
    }

Con este enfoque, no necesita preocuparse acerca de dónde / cuándo se configuran sus registradores log4j. La primera vez que el classpath pregunta por ellos, se construyen perezosamente, se devuelven y se ponen a disposición a través de slf4j. Espero que esto haya ayudado!

IAmYourFaja
fuente
2
¡Justo en el clavo! Muchas gracias por un útil ejemplo! @Oers: gracias por intentar guiarme en la dirección correcta. Voy a darle el cheque verde por su dedicación, pero tengo que darle la recompensa a Zharvey porque era exactamente lo que estaba buscando. Gracias de nuevo a todos!
IAmYourFaja
4

En el caso de que haya definido un apéndice en las propiedades de log4j y desee actualizarlo mediante programación, establezca el nombre en las propiedades de log4j y obtenga el nombre.

Aquí hay una entrada de ejemplo log4j.properties:

log4j.appender.stdout.Name=console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.Threshold=INFO

Para actualizarlo, haga lo siguiente:

((ConsoleAppender) Logger.getRootLogger().getAppender("console")).setThreshold(Level.DEBUG);
Kyle Shrader
fuente
1

Si alguien viene buscando configurar log4j2 mediante programación en Java, entonces este enlace podría ayudar: ( https://www.studytonight.com/post/log4j2-programmatic-configuration-in-java-class )

Aquí está el código básico para configurar un Appender de consola:

ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();

builder.setStatusLevel(Level.DEBUG);
// naming the logger configuration
builder.setConfigurationName("DefaultLogger");

// create a console appender
AppenderComponentBuilder appenderBuilder = builder.newAppender("Console", "CONSOLE")
                .addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
// add a layout like pattern, json etc
appenderBuilder.add(builder.newLayout("PatternLayout")
                .addAttribute("pattern", "%d %p %c [%t] %m%n"));
RootLoggerComponentBuilder rootLogger = builder.newRootLogger(Level.DEBUG);
rootLogger.add(builder.newAppenderRef("Console"));

builder.add(appenderBuilder);
builder.add(rootLogger);
Configurator.reconfigure(builder.build());

Esto reconfigurará el rootLogger predeterminado y también creará un nuevo apéndice .

iamabhishek
fuente