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.
- 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.
- 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
- 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
- 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.
Pingback: Por que o Hibernate 4 não mostra os logs no Log4j2 | Coffee Server