Alterando dinamicamente o nível do log log4j

127

Quais são as diferentes abordagens para alterar o nível de log log4j dinamicamente, para que não precise reimplementar o aplicativo. As mudanças serão permanentes nesses casos?

Ravi
fonte
Muito semelhante ao stackoverflow.com/questions/2115900/…
vsingh
3
Pergunta atualizada para log4j2: stackoverflow.com/questions/23434252/…
slaadvak
1
Observe que (quase) tudo nesta página é sobre log4j, não log4j2. Esta página inteira é tão cheia de confusão e desorientação que é inútil. Vá para stackoverflow.com/questions/23434252/… como @slaadvak recomenda.
Lambart 03/02

Respostas:

86

Alterar o nível do log é simples; modificar outras partes da configuração representará uma abordagem mais aprofundada.

LogManager.getRootLogger().setLevel(Level.DEBUG);

As mudanças são permanentes através do ciclo de vida do Logger. Na reinicialização, a configuração será lida e usada, pois a definição do nível no tempo de execução não persiste na alteração do nível.

ATUALIZAÇÃO: Se você estiver usando o Log4j 2, remova as chamadas de setLevelacordo com a documentação, pois isso pode ser alcançado através das classes de implementação.

As chamadas para logger.setLevel () ou métodos semelhantes não são suportadas na API. Os aplicativos devem removê-los. Funcionalidades equivalentes são fornecidas nas classes de implementação do Log4j 2, mas podem deixar o aplicativo suscetível a alterações nos componentes internos do Log4j 2.

Aaron McIver
fonte
5
Apenas para dependências de tempo de execuçãoLogManager.getLogger(Class.forName("org.hibernate.util.JDBCExceptionReporter")).setLevel(Level.FATAL);
CelinHC
8
Observe que a API log4j 2 não fornece um método "setLevel".
ChrisCantrell
5
Mas isso apenas define o logger raiz, não é? Se níveis individuais forem definidos para os registradores na raiz, a configuração do registrador raiz não terá efeito sobre esses registradores. Não precisaríamos fazer algo como root.getLoggerRepository (). GetCurrentCategories (), iterar sobre cada instância do logger e definir LEVELs para cada logger? @AaronMcIver
TheMonkWhoSoldHisCode
8
O @ChrisCantrell Log4j 2 fornece uma maneira de fazer isso , embora não seja tão simples.
precisa saber é o seguinte
2
O Log4j2 pode ser configurado para atualizar sua configuração, varrendo o arquivo log4j2.xml (ou equivalente) em intervalos determinados. Por exemplo, <Configuration status = "warn" monitorInterval = "5" name = "tryItApp" packages = "">
Kimball Robinson
89

Arquivo Watchdog

O Log4j pode observar o log4j.xmlarquivo quanto a alterações na configuração. Se você alterar o arquivo log4j, o log4j atualizará automaticamente os níveis de log de acordo com suas alterações. Consulte a documentação de org.apache.log4j.xml.DOMConfigurator.configureAndWatch(String,long) para obter detalhes. O tempo de espera padrão entre as verificações é de 60 segundos. Essas alterações seriam persistentes, pois você altera diretamente o arquivo de configuração no sistema de arquivos. Tudo o que você precisa fazer é chamar DOMConfigurator.configureAndWatch () uma vez.

Cuidado: o método configureAndWatch não é seguro para uso em ambientes J2EE devido a um vazamento de Encadeamento

JMX

Outra maneira de definir o nível de log (ou reconfigurar em geral) log4j é usando o JMX. O Log4j registra seus registradores como JMX MBeans. Usando os consoles MBeanServer dos servidores de aplicativos (ou o jconsole.exe do JDK), é possível reconfigurar cada registrador individual. Essas alterações não são persistentes e seriam redefinidas para a configuração conforme definida no arquivo de configuração após a reinicialização do aplicativo (servidor).

Self made

Conforme descrito por Aaron, você pode definir o nível de log programaticamente. Você pode implementá-lo em seu aplicativo da maneira que gostaria que acontecesse. Por exemplo, você pode ter uma GUI em que o usuário ou administrador altera o nível do log e, em seguida, chama os setLevel()métodos no logger. Se você mantém as configurações em algum lugar ou não, é com você.

mhaller
fonte
8
Uma palavra de cautela em relação à abordagem do log4j watchdog: "Como o configureAndWatch inicia um encadeamento de watchdog separado e como não há como interromper esse encadeamento no log4j 1.2, o método configureAndWatch não é seguro para uso em ambientes J2EE em que os aplicativos são reciclados". Referência: Log4J FAQ
Somu
Se eu fosse usar a funcionalidade configureAndWatch do Log4j, poderia interromper esse segmento de watchdog no método @PostDestroy do EJB (esse é um indicador suficientemente bom de quando o contêiner está sendo desligado) É isso? Ou há mais do que estou perdendo ..!
precisa saber é o seguinte
desculpe eu quis dizer @PreDestroy método
bajaj robin
"O Log4j registra seus loggers como JMX MBeans. ". Meu servlet usa log4j 1.2. Não vejo nenhum MBeans log4j.
Abdull
Tudo o que você precisa fazer é chamar DOMConfigurator.configureAndWatch () uma vez. Como posso conseguir isso?
gstackoverflow
5

O Log4j2 pode ser configurado para atualizar sua configuração, varrendo o arquivo log4j 2 .xml (ou equivalente) em intervalos determinados. Basta adicionar o parâmetro " monitorInterval " à sua marca de configuração. Consulte a linha 2 do arquivo log4j 2 .xml de amostra , que instrui o log4j a verificar novamente sua configuração se mais de 5 segundos se passaram desde o último evento de log.

<?xml version="1.0" encoding="UTF-8" ?>
<Configuration status="warn" monitorInterval="5" name="tryItApp" packages="">

    <Appenders>
        <RollingFile name="MY_TRY_IT"
                     fileName="/var/log/tryIt.log"
                     filePattern="/var/log/tryIt-%i.log.gz">
            <Policies>
                <SizeBasedTriggeringPolicy size="25 MB"/>
            </Policies>
            ...
        </RollingFile>
    </Appenders>


    <Loggers>
        <Root level="error">
            <AppenderRef ref="MY_TRY_IT"/>
        </Root>
    </Loggers>

</Configuration>

Existem etapas extras para fazer isso funcionar se você estiver implantando em uma instância do tomcat, dentro de um IDE ou ao usar a inicialização por mola. Isso parece um pouco fora do escopo aqui e provavelmente merece uma pergunta separada.

Kimball Robinson
fonte
@vsingh, você está implantando dentro de boot de primavera, tomcat ou contêiner ou com um IDE? Às vezes, pode haver etapas extras nesses casos (não é culpa do log4j2) - basicamente, o aplicativo não pode ver o arquivo sendo alterado porque ele foi copiado para outro local por uma estrutura ou ferramenta.
Kimball Robinson
Oi Eu testei isso no Jboss6.4 e atualizei o arquivo de configuração log4j2 sob o local (dentro do arquivo .war) onde o aplicativo pode ver o arquivo. No entanto, ainda não funcionou. Alguma sugestão?
MidTierDeveloper 27/02/19
3

Esta resposta não ajudará você a alterar o nível de log dinamicamente, você precisará reiniciar o serviço; se você estiver bem em reiniciar o serviço, use a solução abaixo

Fiz isso para alterar o nível de log do log4j e funcionou para mim; não enviei nenhum documento. Eu usei esse valor de propriedade do sistema para definir meu nome do arquivo de log. Eu usei a mesma técnica para definir o nível de log também, e funcionou

passou isso como parâmetro da JVM (eu uso Java 1.7)

Desculpe, isso não altera dinamicamente o nível de log, requer uma reinicialização do serviço

java -Dlogging.level=DEBUG -cp xxxxxx.jar  xxxxx.java

no arquivo log4j.properties, adicionei esta entrada

log4j.rootLogger=${logging.level},file,stdout

eu tentei

 java -Dlogging.level=DEBUG -cp xxxxxx.jar  xxxxx.java
 java -Dlogging.level=INFO-cp xxxxxx.jar  xxxxx.java
 java -Dlogging.level=OFF -cp xxxxxx.jar  xxxxx.java

Tudo funcionou. espero que isto ajude!

Eu tenho as seguintes dependências no meu pom.xml

<dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
</dependency>

<dependency>
    <groupId>log4j</groupId>
    <artifactId>apache-log4j-extras</artifactId>
    <version>1.2.17</version>
</dependency>
Anandkumar
fonte
2
Tudo o que você mencionou parece estar bem, mas a questão é alterar dinamicamente o nível de log.
Azim
Para fazer isso, você precisa reiniciar o serviço. Isso não altera os níveis de log dinamicamente.
kk.
2

Com o log4j 1.x, acho que a melhor maneira é usar um DOMConfigurator para enviar um de um conjunto predefinido de configurações de log XML (por exemplo, uma para uso normal e outra para depuração).

O uso destes pode ser feito com algo como isto:

  public static void reconfigurePredefined(String newLoggerConfigName) {
    String name = newLoggerConfigName.toLowerCase();
    if ("default".equals(name)) {
      name = "log4j.xml";
    } else {
      name = "log4j-" + name + ".xml";
    }

    if (Log4jReconfigurator.class.getResource("/" + name) != null) {
      String logConfigPath = Log4jReconfigurator.class.getResource("/" + name).getPath();
      logger.warn("Using log4j configuration: " + logConfigPath);
      try (InputStream defaultIs = Log4jReconfigurator.class.getResourceAsStream("/" + name)) {
        new DOMConfigurator().doConfigure(defaultIs, LogManager.getLoggerRepository());
      } catch (IOException e) {
        logger.error("Failed to reconfigure log4j configuration, could not find file " + logConfigPath + " on the classpath", e);
      } catch (FactoryConfigurationError e) {
        logger.error("Failed to reconfigure log4j configuration, could not load file " + logConfigPath, e);
      }
    } else {
      logger.error("Could not find log4j configuration file " + name + ".xml on classpath");
    }
  }

Apenas chame isso com o nome de configuração apropriado e certifique-se de colocar os modelos no caminho de classe.

ISparkes
fonte
qual é o ponto de disparo desse método? como ele sabe que esse método precisa ser chamado sempre que houver uma alteração na configuração do log4j?
31/03/16
Ainda não entendi o que você quer dizer "sob demanda". Você pode mostrar um trecho onde você conecta esse método?
precisa saber é
2
Aqui está: Este é um trecho do Controller onde o usamos. Temos uma página de administração com alguns links para reconfigurar dinamicamente o log, o que gera um GET para o link / admin / setLogLevel? Level = Erro e capturamos isso no controlador como este @RequestMapping (value = "setLogLevel", method = RequestMethod.GET) public ModelAndView setLogLevel (@RequestParam (value = "level", required = true) Nível da string) {Log4jReconfigurator.reconfigureExisting (level);
ISparkes
Assim, "on demand" significa "Quando o usuário clica no botão" no meu caso
ISparkes
Ah, peguei você. Portanto, seu console administrativo precisa fazer uma solicitação para chamar esse método.
ASGs
0

Eu usei esse método com êxito para reduzir a verbosidade dos logs "org.apache.http":

ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("org.apache.http");
logger.setLevel(Level.TRACE);
logger.setAdditive(false);
Thomas Bernardin
fonte
0

Para a API log4j 2, você pode usar

Logger logger = LogManager.getRootLogger();
Configurator.setAllLevels(logger.getName(), Level.getLevel(level));
mohamed stitane
fonte
-1

Se você deseja alterar o nível de log de todos os loggers, use o método abaixo. Isso enumerará todos os registradores e alterará o nível de registro para o nível especificado. Por favor, verifique se você NÃO possui log4j.appender.loggerName.Threshold=DEBUGpropriedades definidas no seu log4j.propertiesarquivo.

public static void changeLogLevel(Level level) {
    Enumeration<?> loggers = LogManager.getCurrentLoggers();
    while(loggers.hasMoreElements()) {
        Logger logger = (Logger) loggers.nextElement();
        logger.setLevel(level);
    }
}
kk.
fonte
-3

Você pode usar o seguinte snippet de código

((ch.qos.logback.classic.Logger)LoggerFactory.getLogger(packageName)).setLevel(ch.qos.logback.classic.Level.toLevel(logLevel));
user2606570
fonte
Eu tenho que tentar.
user2045474