Configuração e utilização do Log4j2

O Log4j é um dos frameworks de log mais utilizados, se não for o mais utilizado – no mundo Java.

No post de hoje eu vou colocar um resumão com as configurações do Log4j2 e alguns detalhes que devem ser observados para que tudo funcione sem dor de cabeça.

Novidades do Log4j2

  • Agora é possível utilizar JSON ou YAML no arquivo de configuração além de XML
  • A configuração através de arquivo properties foi removida
  • O arquivo XML de configuração utilizado na versão 1.2 não é compatível com a versão 2
  • Muitas melhorias de performance foram implementadas na versão 2, principalmente para cenários de log assíncronos
  • Possibilidade de aplicar filtros nos logs, ou seja, antes de passar o log para Loggers ou Appenders o log propriamente dito pode ser encaminhado para um classe de filtro
  • Suporte para substituição de propriedades, algo parecido com o funcionamento do Maven onde é possível declarar propriedades e depois fazer referência as mesmas
  • Suporte a reconfiguração automática quando o arquivo de configuração é modificado
  • Agora o log4j está dividido entre vários jar e não em somente em um como na versão 1.2
  • Requer no mínimo Java 6

São muitas novidades legais, mas a que menos me agradou foi a retirada do arquivo de properties para fazer a configuração de log. Gostava do arquivo de propriedades por achar mais fácil de ler e entender. Destaco duas novidades que achei bem legal, o “reload” automático do arquivo de configuração e o suporte a substituição de propriedades, além da tradicional melhoria de performance.

Configuração

Para configurar o Log4j2 eu optei por utilizar o arquivo XML. Uma importante mudança é o nome do arquivo que o Log4j2 procura no classpath da aplicação, no caso de xml o nome deve ser log4j2.xml. A extensão poderia ser json ou jsn para JSON ou ainda yaml ou yml para YAML. Também vale lembrar que é possível adicionar um arquivo de configuração para ambientes de testes, neste caso é necessário adicionar “-test” ao nome do arquivo e manter a extensão, algo como lo4j2-test.xml. Os arquivos de configuração do tipo teste tem preferência sobre os arquivos de produção. Mais informações sobre a ordem de leitura dos arquivos de configuração podem ser obtidas aqui.

Exemplo de XML:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug">
    <Properties>
        <Property name="pattern">%d{dd/MM/yyyy HH:mm:ss,SSS EEEE} %p [%-20c{1}] %m%n</Property>
        <Property name="filePath">${sys:user.home}</Property>
    </Properties>
    <Appenders>
        <RollingFile name="RollingFile"
                     fileName="${filePath}/logs/meuLog.log"
                     filePattern="${filePath}/logs/meuLog-%d{dd-MM-yyyy-HH:mm:ss}-%i.log">
            <PatternLayout pattern="${pattern}"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="10 MB" />
            </Policies>
            <DefaultRolloverStrategy max="20"/>
        </RollingFile>
        
        <Console name="Console">
            <PatternLayout pattern="${pattern}"/>
        </Console>
    </Appenders>
    
    <Loggers>
        <Root level="debug">
            <AppenderRef ref="RollingFile"/>
            <AppenderRef ref="Console"/>
        </Root>
        
          <Logger name="org.hibernate" level="debug" additivity="false">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="RollingFile"/>
        </Logger>
    </Loggers>
    
</Configuration>

Troubleshooting

Acho importante destacar alguns pontos do arquivo de configuração.

  1. Não existe ainda nenhum XSD ou DTD (pelo menos no momento em que escrevo esse post) para validar o arquivo de configuração. O que na minha opinião é um grande erro, dai a importância do atributo status=”debug” na tag Configuration, pelo menos em ambiente de desenvolvimento e testes, dessa forma o Log4j2 ao parsear o arquivo mostra no log os erros caso existam. Como não existe nenhum autocomplete das IDE’s um exemplo comum de erro é errar o nome da tag, é preciso ficar atento pois esse parser vai ser executado somente na primeira execução do Log4j2.

  2. A documentação do Log4j2 diz que é possível declarar um property usando a seguinte sintaxe:
    <Property name="pattern" value="%d{dd/MM/yyyy HH:mm:ss,SSS EEEE} %p [%-20c{1}] %m%n"/>

    Mas não funcionou, pelo menos comigo, o Log4j2 mostra o seguinte erro ao realizar o parser: Property contains an invalid element or attribute “value”. Não sei se é um bug, dei uma olhada rápida na internet e não encontrei nada relacionado

  3. A property com o nome filePath possui o valor ${sys:user.home}. É dessa forma que o Log4j2 busca por variáveis de sistema, não é possível utilizar diretamente ${user.home} pois o Log4j2 vai procurar por uma propriedade com esse nome. Existe outras configurações que permitem ao Log4j2 ler as variáveis a partir de outras fontes, mais detalhes aqui

  4. Por fim, mas não menos importante, reparem no atributo additivity=”false” da tag Logger. Essa tag evita que o log seja duplicado, primeiro o Log4j passa o log para o Appender e depois para o Root que contém a referência para Appender e bingo! log duplicado

Dependências

Como falei no começo do post, agora é preciso utilizar mais de uma arquivo jar. Como utilizo Maven, a minha configuração dessa maneira:

 
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.2</version>
        </dependency>
        
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.2</version>
        </dependency>
        
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-web</artifactId>
            <version>2.2</version>
        </dependency>

Além da API e core adicionei o módulo web, dessa forma ao realizar o deploy o Log4j2 já procura o arquivo de configuração e faz o parser. Se algo de errado acontecer, ele já informa na hora. Sem esse módulo o parser é realizado na primeira chamada ao Log4j2, o que pode demorar um pouco para acontecer e ainda custar mais tempo na realização de outro deploy.

Como no meu caso eu utilizo o Slf4j que é uma fachada para outras implementações de log tal como java.util.logging, logback, log4j, etc é necessário adicionar mais duas dependências:

         <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.2</version>
        </dependency>
        
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.10</version>
        </dependency>

Usando o Log4j2

Para usar basta declarar o seguinte atributo de classe:

private static final Logger logger = LogManager.getLogger(NomeDaClasse.class);

E usar da seguinte forma:

logger.debug("Teste");

Os imports para esse esse exemplo são:

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

O Log4j2 possui os seguinte níveis de log: trace, debug, info, warn, error e fatal. Sendo trace o nível mais baixo e fatal o nível mais alto, esse um conceito importante, pois ao definir no arquivo de configuração o level de debug no Logger todo o log que estiver abaixo desse nível será ignorado. Exemplo level=”warn” faz com que os logs com logger.debug não sejam logados.

Para quem utiliza Slf4j o código é quase o mesmo e não muda nada em função de ser o Log4j2.

Até a próxima.

Esse post foi publicado em Desenvolvimento e marcado . Guardar link permanente.

Uma resposta para Configuração e utilização do Log4j2

  1. Pingback: Por que o Hibernate 4 não mostra os logs no Log4j2 | Coffee Server

Deixe um comentário