Configurando os Registradores Log4j Programaticamente

189

Estou tentando usar SLF4J (com log4jligação) pela primeira vez.

Gostaria de configurar três loggers nomeados diferentes que podem ser retornados por um LoggerFactory que registrará níveis diferentes e enviará as mensagens para diferentes anexos:

  • Registrador 1 "FileLogger" registra DEBUG e anexa a DailyRollingFileAppender
  • O registrador 2 "TracingLogger" registra TRACE + e anexa a um JmsAppender
  • O registrador 3 "ErrorLogger" registra o erro + e anexa a um JmsAppender

Além disso, eu quero que eles sejam configurados programaticamente (em Java, em vez de XML ou um log4j.propertiesarquivo).

Eu imagino que, normalmente, eu definiria esses Loggers em algum lugar de algum código de inicialização, como um init()método. No entanto, como quero usar slf4j-log4j, estou confuso sobre onde eu poderia definir os criadores de logs e disponibilizá-los para o caminho de classe.

Não acredito que isso seja uma violação do objetivo subjacente do SLF4J (como fachada), porque meu código usando a API do SLF4J nunca saberá que esses registradores existem. Meu código apenas faz chamadas normais para a API SLF4J, que as encaminha para os log4j Loggers que encontra no caminho de classe.

Mas como faço para configurar esses log4j Loggers no caminho de classe ... em Java ?!

IAmYourFaja
fonte
3
Para log4j 1.x, use a resposta aceita abaixo para 2.x, consulte logging.apache.org/log4j/2.x/manual/customconfig.html
earcam

Respostas:

277

Você pode adicionar / remover Appender programaticamente no 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

Eu sugiro que você o coloque em um init () em algum lugar, onde você tenha certeza, que isso será executado antes de qualquer outra coisa. Você pode remover todos os anexos existentes no registrador raiz com

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

e comece adicionando o seu. Você precisa do log4j no caminho da classe para que isso funcione.

Observação:
você pode Logger.getLogger(...)adicionar o que quiser para adicionar anexos. Acabei de usar o registrador raiz porque ele está na parte inferior de todas as coisas e lidará com tudo o que é passado por outros apêndices em outras categorias (a menos que configurado de outra forma, definindo o sinalizador de aditividade).

Se você precisar saber como o registro funciona e como é decidido onde os registros são gravados, leia este manual para obter mais informações sobre isso.
Em resumo:

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

lhe dará um logger para a categoria "com.fizz".
Para o exemplo acima, isso significa que tudo o que estiver conectado a ele será consultado no console e no apêndice do arquivo no registrador raiz.
Se você adicionar um appender ao Logger.getLogger ("com.fizz"). AddAppender (newAppender), o log fizzserá processado por todos os anexos do logger raiz e do newAppender.
Você não cria registradores com a configuração, apenas fornece manipuladores para todas as categorias possíveis no seu sistema.

oers
fonte
2
Obrigado oers! Pergunta rápida - notei que você está adicionando os anexos ao Logger raiz. Existe uma razão para isso?
IAmYourFaja
E, mais importante, precisarei especificar qual Logger recuperar do LoggerFactory do SLF4J. É possível solicitar ao SLF4J o logger raiz do log4j?
IAmYourFaja
3
@AdamTannon Você pode pegar qualquer Logger.getLogger (...) que quiser. Acabei de usar o registrador raiz porque ele está na parte inferior de todas as coisas e lidará com tudo o que é passado por outros anexadores em outras categorias (a menos que configurado de outra forma). Veja hierarquia de
loggers
@AdamTannon, você não pode usar o sl4j factory para obter o log4j root logger. SL4j é uma fachada de registro. Você não receberá nada específico do log4j.
Oers
2
oers - Agradeço seu feedback maravilhoso, mas não estou conectando todos os pontos aqui. Você pode modificar o seu exemplo para mostrar a adição de um novo Logger (não o root logger) que, uma vez adicionado ao sistema, estará disponível para qualquer outra classe que solicitar? Por exemplo, um criador de logs que normalmente seria acessado por, Logger fizz = LoggerFactory.getLogger("com.fizz");obrigado , obrigado!
IAmYourFaja
47

Parece que você está tentando usar o log4j de "ambas as extremidades" (a extremidade do consumidor e a extremidade da configuração).

Se você deseja codificar contra a slf4j api, mas determinar antecipadamente (e programaticamente) a configuração dos log4j Loggers que o caminho de classe retornará, é absolutamente necessário ter algum tipo de adaptação de log que utilize construção lenta.

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);
    }

Com essa abordagem, você não precisa se preocupar com onde / quando os loggers do log4j são configurados. Na primeira vez em que o caminho da classe pede, eles são construídos preguiçosamente, devolvidos e disponibilizados via slf4j. Espero que isso tenha ajudado!

IAmYourFaja
fonte
2
Acertou em cheio! Muito obrigado por um exemplo útil! @Oers - obrigado por tentar me orientar na direção certa - eu vou dar o cheque verde por sua dedicação, mas tenho que dar a zharvey a recompensa, porque era exatamente o que eu estava procurando. Mais uma vez obrigado a todos!
IAmYourFaja
4

No caso de você ter definido um appender nas propriedades do log4j e desejar atualizá-lo programaticamente, defina o nome nas propriedades do log4j e obtenha-o pelo nome.

Aqui está um exemplo de entrada 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 atualizá-lo, faça o seguinte:

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

Se alguém procurar configurar o log4j2 programaticamente em Java, esse link poderá ajudar: ( https://www.studytonight.com/post/log4j2-programmatic-configuration-in-java-class )

Aqui está o código básico para configurar um Console Appender:

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());

Isso reconfigurará o rootLogger padrão e também criará um novo aplicativo .

iamabhishek
fonte