Exemplo Tutorial do Log4j2 – Configuração, Níveis, Anexadores

Bem-vindo ao Tutorial de Exemplo do Log4j2 Apache. Se você perguntar a um desenvolvedor especializado sobre a coisa mais irritante em uma aplicação, a resposta pode estar relacionada ao registro. Se não houver um registro adequado em uma aplicação, a manutenção será um pesadelo. A maioria das aplicações passa por testes de desenvolvimento, testes unitários, testes de integração. Mas quando se trata de produção, você sempre enfrentará cenários e exceções únicos. Portanto, a única maneira de descobrir o que aconteceu em um caso específico é depurar através dos registros. Muitos frameworks fornecem alguma forma de registro padrão, mas sempre é melhor seguir o mecanismo de registro padrão da indústria. O Apache Log4j é um dos frameworks de registro mais amplamente utilizados. O Apache Log4j 2 é a próxima versão, que é muito melhor que o Log4j.

Tutorial de Exemplo do Log4j

Neste Tutorial de Exemplo do Log4j2, você aprenderá como começar com o Apache Log4j2. Também exploraremos a arquitetura do Log4j2, configuração do Log4j2, níveis de registro do Log4j2, anexadores, filtros e muito mais.

  1. Visão Geral do Log4j2
  2. Arquitetura do Log4j2
  3. Configuração do Log4j2
  4. Níveis do Log4j2
  5. Consultas do Log4j2
  6. Anexadores do Log4j2
  7. Filtros do Log4j2
  8. Layouts do Log4j2
  9. Qual Nível do Log4j2 você deve usar
  10. Resumo do Tutorial do Log4j2

Visão Geral do Log4j2

O uso da API de logging na aplicação não é um luxo, é uma necessidade. O Log4j é uma biblioteca de código aberto publicada e licenciada sob a Apache Software. Você pode depurar uma aplicação usando o Eclipse Debugging ou outras ferramentas, mas isso não é suficiente e viável em um ambiente de produção. O mecanismo de logging fornecerá vários benefícios que você não encontrará na depuração normal.

Category / Operation (Debugging, Logging) Debugging Logging
Human Intervention There’s a need for human intervention No need for human intervention
Persistent Medium Can’t be integrated with persistent storage Can be integrated with persistent storage (Files, Database, NoSQL database, etc.)
May used for Auditing Can’t be used for achieving auditing Can be used for achieving auditing if it’s used efficiently
Sufficient for complicated structure and flow Not sufficient; you may get lost with flow. Sufficient
Productivity Less productive More productive

Como você pode ver acima, o uso do mecanismo de logging será mais eficiente com menor custo de manutenção. O Apache Log4j é a principal ferramenta para logging em aplicações Java, então você deve usá-lo.

Arquitetura do Log4j2

Antes de avançarmos para o tutorial de Exemplo do Log4j, é bom dar uma olhada na arquitetura do Log4j2. A imagem abaixo mostra as classes importantes na API do Log4j2. Aqui está a explicação detalhada para a arquitetura mostrada acima:

  • As aplicações solicitarão ao LogManager um Logger com um nome específico.

  • O LogManager localizará o LoggerContext apropriado e então obterá o Logger dele.

  • Se o Logger ainda não foi criado, ele será criado e associado ao LoggerConfig de acordo com três opções abaixo:

    1. A instância do Logger será criada e associada ao LoggerConfig que possui o mesmo nome. Por exemplo, a classe App em getLogger(App.class) será avaliada como uma String com.journaldev.App. O nome do LoggerConfig é idêntico ao nome da classe totalmente qualificada (Componente de software).
    2. A instância do Logger será criada e associada ao LoggerConfig que possui o mesmo pacote pai dos Loggers. Por exemplo, com.journaldev em getLogger("com.journaldev")
    3. A instância do Logger será criada e associada ao LoggerConfig raiz. O LoggerConfig raiz será usado quando não houver arquivo de configuração ou quando você estiver obtendo um logger com um nome não definido nas declarações de logger.
  • Objetos Configurador de Registro são criados a partir da declaração do Registro no arquivo de configuração. O Configurador de Registro também é usado para lidar com Eventos de Registro e delegá-los para seus Apêndices Log4j2 definidos.

  • O registro raiz é um caso excepcional, em termos de sua existência. Ele sempre existe e está no topo de qualquer hierarquia de registros.

  • Você pode obter o registro raiz usando as seguintes instruções:

    Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
    Logger logger = LogManager.getRootLogger();
    
  • O nome dos registros do log4j2 é sensível a maiúsculas e minúsculas.

  • Exceto o registro raiz, todos os registros podem ser obtidos passando seu nome para LogManager.getLogger().

  • O LoggerContext é um ponto vocal para o sistema de Log, pois você pode ter múltiplos LoggerContexts dentro de sua aplicação. Para cada LoggerContext, uma configuração ativa deve ser definida.

  • A configuração do Log4j2 contém todos os ativos do sistema de Log; LoggerConfig(s), Appender(s), Filter(s) e muitos outros.

  • A chamada de LogManager.getLogger() passando o mesmo nome sempre retornará a referência para a mesma instância exata do logger.

  • A configuração do sistema de Log é tipicamente feita durante a inicialização da aplicação. Isso pode ser feito de diferentes formas; programaticamente ou lendo um arquivo de configuração do log4j2.

Cada registador está associado a um objeto LoggerConfig, conjunto de objetos LoggerConfig compõem uma Hierarquia de registradores. Este conceito é conhecido como Hierarquia de Registadores. Hierarquia de Registadores é composta por um conjunto de objetos LoggerConfig com uma relação pai-filho. O elemento mais alto em cada Hierarquia de Registadores é o Registrador Raiz. Se o Log4j2 não encontrar o arquivo de configuração, apenas o Registrador Raiz será usado para registro com o nível de registro como ERRO. Abaixo está a mensagem de aviso que você receberá nesse caso. StatusLogger de Erro Nenhum arquivo de configuração do log4j2 encontrado. Usando configuração padrão: registrando apenas erros no console. A tabela abaixo mostra a relação pai-filho na Hierarquia de Registadores.

LoggerConfig (Is A) Root com com.journaldev com.journaldev.logging
Root X Child descendant descendant
com Parent X Child descendant
com.journaldev Ancestor Parent X Child
com.journaldev.logging Ancestor Ancestor Parent X

Para esclarecer a relação pai-filho, a tabela acima seria lida da seguinte forma:

  • Root é pai de com.
  • Root é um ancestral de com.journaldev.
  • Root é um ancestral de com.journaldev.logging.
  • com é filho de Root.
  • com é pai de com.journaldev.
  • com é um ancestral de com.journaldev.logging.
  • com.journaldev.logging é filho de com.journaldev e assim por diante.

Uma instância de LoggerConfig é considerada um ancestral de outro LoggerConfig se o seu nome seguido de um ponto for um prefixo para o nome do descendente. Uma instância de LoggerConfig é considerada um pai de outro LoggerConfig se não houver nomes intercalados entre os dois.

Configuração do Log4j2

Há muitas maneiras de usar a configuração do Log4j2 em sua aplicação.

  1. Usando um arquivo de configuração escrito em XML, JSON, YAML ou arquivo de propriedades.
  2. Programaticamente, criando uma fábrica de configuração e implementação de configuração.
  3. Programaticamente, chamando APIs expostas na interface de configuração.
  4. Programaticamente, chamando métodos na classe de logger interna.

Vamos nos concentrar principalmente no arquivo de configuração. No entanto, é bom conhecer a abordagem de programação também, caso você queira configurar uma estratégia de registro específica para algum Logger específico. Primeiro, vamos considerar o caso em que você não forneceu um arquivo de configuração. A implementação do Log4j2 assume que há uma variável de Sistema chamada log4j.configurationFile para apontar a localização do arquivo de configuração do log4j2.

package com.journaldev;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class App
{
    public static void main( String[] args ) {
    	Logger logger = LogManager.getRootLogger();
    	logger.trace("Configuration File Defined To Be :: "+System.getProperty("log4j.configurationFile"));
    }
}

A simple log4j2 configuration file will look like below. configuration.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="trace">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

E aqui está a explicação detalhada para o código listado acima:

  • O aplicativo referenciou o logger Root chamando o método getRootLogger do LogManager.
  • A referência do logger do LogManager iniciou o sistema Log4j.
  • Log4j irá inspecionar a propriedade do sistema log4j.configurationFile para determinar o arquivo de configuração do Log4j2. A configuração do Log4j pode ser escrita em JSON, YAML e XML.
  • Podemos definir a propriedade do sistema log4j.configurationFile através do System.setProperties("log4j.configurationFile","CAMINHO_DO_ARQUIVO") ou passando-a como um parâmetro JVM como visto na figura abaixo. Note também o prefixo do protocolo de arquivo.

  • Caso nenhuma propriedade do sistema seja definida, a ordem de configuração segue a seguinte precedência:
    • A Configuração de Propriedades procurará por log4j2-test.properties no classpath.
    • A Configuração YAML procurará por log4j2-test.yaml ou log4j2-test.yml no classpath.
    • A Configuração JSON procurará por log4j2-test.jsn ou log4j2-test.json no classpath.
    • A Configuração XML procurará por log4j2-test.xml no classpath.
    • A Configuração de Propriedades procurará por log4j2.properties no classpath
    • A Configuração YAML procurará por log4j2.yml ou log4j2.yaml no classpath.
    • A Configuração JSON procurará por log4j2.jsn ou log4j2.json no classpath.
    • A Configuração XML procurará por log4j2.xml no classpath.
    • Se nenhum arquivo de configuração foi fornecido, a DefaultConfiguration será utilizada e isso levará a um conjunto de comportamentos padrão:
      • O logger raiz será utilizado.
      • O nível do logger raiz será definido como ERROR.
      • O logger raiz propagará mensagens de log para o console.
      • O PatternLayout será definido como %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n

O uso do arquivo de configuração log4j2 torna a configuração do log4j2 tão simples, mas vamos ver como podemos configurá-lo programaticamente. Isso é tudo sobre o uso do ConfigurationFactory.

package com.journaldev;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.xml.XmlConfigurationFactory;
import org.apache.logging.log4j.core.layout.PatternLayout;
public class App
{
    public static void main( String[] args ) throws FileNotFoundException, IOException {
 
    	// Obtenha uma instância da fábrica de configuração; suas opções são a Fábrica de Configuração padrão, Fábrica de Configuração XML,
    	// Fábrica de Configuração Yaml e Fábrica de Configuração Json
    	ConfigurationFactory factory =  XmlConfigurationFactory.getInstance();
 
    	// Localize a origem desta configuração, este arquivo localizado é um arquivo fictício que contém apenas uma Tag de configuração vazia
    	ConfigurationSource configurationSource = new ConfigurationSource(new FileInputStream(new File("C:/dummyConfiguration.xml")));
 
    	// Obtenha uma referência da configuração
    	Configuration configuration = factory.getConfiguration(configurationSource);
 
    	// Crie o apêndice padrão do console
    	ConsoleAppender appender = ConsoleAppender.createDefaultAppenderForLayout(PatternLayout.createDefaultLayout());
 
    	// Adicione o apêndice do console na configuração
    	configuration.addAppender(appender);
 
    	// Crie LoggerConfig
    	LoggerConfig loggerConfig = new LoggerConfig("com",Level.FATAL,false);
 
    	// Adicione o apêndice
    	loggerConfig.addAppender(appender,null,null);
 
    	// Adicione o logger e associe-o com a instância de loggerConfig
    	configuration.addLogger("com", loggerConfig);
 
    	// Obtenha a instância de contexto
    	LoggerContext context = new LoggerContext("JournalDevLoggerContext");
 
    	// Inicie o sistema de log
    	context.start(configuration);
 
    	// Obtenha uma referência para o logger
    	Logger logger = context.getLogger("com");
 
    	// LogEvent da mensagem DEBUG
    	logger.log(Level.FATAL, "Logger Name :: "+logger.getName()+" :: Passed Message ::");
 
    	// LogEvent da mensagem de erro para o Logger configurado como FATAL
    	logger.log(Level.ERROR, "Logger Name :: "+logger.getName()+" :: Not Passed Message ::");
 
    	// LogEvent da mensagem de ERRO que será tratada pela raiz
    	logger.getParent().log(Level.ERROR, "Root Logger :: Passed Message As Root Is Configured For ERROR Level messages");
    }
}
  • Você pode usar qualquer ConfigurationFactory fornecida pelo Log4j2 ou usar a padrão. Utilizamos a XMLConfigurationFactory para obter uma instância da ConfigurationFactory.
  • A fábrica fornecerá uma instância da referência de Configuração necessária ao passar o arquivo de configuração correspondente.
  • A instância de Configuração será usada em conjunto com LoggerContext para iniciar o Sistema de Log.
  • A console Appender has been configured and added into configuration instance with default layout. This Appender would print out messages into your console.
  • A instância de LoggerConfig foi criada com o nome, NÍVEL e sem filtro fornecidos. O apêndice criado será atribuído a esta instância de LoggerConfig.
  • A instância de LoggerConfig foi adicionada à instância de configuração.
  • A new instance of LoggerContext is created with defined name.
  • A instância de configuração foi passada para a instância LoggerContext e invocada start nesta última.
  • A logger instance has been acquired from LoggerContext. This logger instance will be used to fire set of Log events.
  • A instância Logger disparou três eventos que serão explicados na seção Níveis do Log4j2.
  • O logger com está configurado para imprimir mensagens cujos níveis são FATAIS.
  • Por padrão, o logger raiz está configurado para imprimir mensagens cujos níveis são ERRO.
  • Mensagens de ERRO não serão registradas pelo logger ‘com’ porque seu nível é FATAL.

A mesma configuração pode ser feita usando YAML, JSON ou arquivo de propriedades. No entanto, a configuração do arquivo de propriedades do log4j2 é diferente do arquivo de propriedades do log4j, então certifique-se de não estar tentando usar a configuração do arquivo de propriedades do log4j com o log4j2. Isso causará o seguinte erro;

ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.

Ao processar o código acima, você obterá a seguinte saída:

Logger Name :: com :: Passed Message ::
00:01:27.705 [main] ERROR - Root Logger:: Passed Message As Root Is Configured For ERROR Level messages

A primeira linha de logs é do logger com e a segunda é do Logger Raiz. A mensagem de erro do logger com não é impressa porque seu nível é FATAL.

Níveis do Log4j2

Você pode ver nos exemplos de código acima que toda vez que definimos um LoggerConfig, também fornecemos o nível de registro. Por padrão, o log4j2 é aditivo. Isso significa que todos os loggers pai também serão usados quando um logger específico for usado. A imagem abaixo esclarece essa situação. E aqui estão pontos de esclarecimento para isso:

  • Como afirmamos anteriormente, cada logger está associado a uma instância de LoggerConfig. Este LoggerConfig foi definido no escopo de configuração.
  • O nível de registro pode ser determinado no escopo do LoggerConfig.
  • Você pode obter o logger pelo seu nome, pacote pai ou apontando diretamente para o Root Logger.
  • O Root Logger é o nó de nível superior para toda a hierarquia do LoggerConfig.
  • Uma vez que você obtenha o logger com.journaldev e inicie um logEvent para registro, o loggerConfig (net.journaldev) registrará a mensagem e a mensagem será propagada também na hierarquia sem respeitar os níveis de registro dos pais. Portanto, o evento de log será propagado para os loggers com e Root e eles também registrarão a mensagem respectivamente de acordo com os níveis definidos.
  • Uma vez que você obtenha o logger com e inicie um logEvent para registro, o loggerConfig (com) registrará a mensagem e a mensagem será propagada também na hierarquia sem respeitar os níveis de registro dos pais. Ou seja, o Root logger será propagado o evento de log e ele também registrará a mensagem.
  • O mesmo caso para a hierarquia net.journaldev.
  • Próximas seções, serão adicionadas mais esclarecimentos para o conceito aditivo.
  • Existe a possibilidade de o pai ignorar a mensagem usando o conceito de Filtro ou configurando o indicador aditivo como falso, assim eventos de log não serão propagados para os pais.
  • Existe a possibilidade de o registrador de logs ignorar a mensagem se o nível de log da respectiva configuração do registrador for MAIOR QUE o nível dos eventos de log.

Agora, vamos ver o exemplo associado ao conceito de aditividade explicado acima:

import net.NetApp;
import net.journaldev.NetJournalDevApp;
import com.ComApp;
import com.journaldev.ComJournalDevApp;
public class Main {
	public static void main(String [] args){
		new ComApp();
		new ComJournalDevApp();
		new NetApp();
		new NetJournalDevApp();
	}
}
package com.journaldev;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class ComJournalDevApp {
	public ComJournalDevApp(){
		Logger logger = LogManager.getLogger(ComJournalDevApp.class);
		logger.trace("COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::");
	}
}
package net;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class NetApp {
	public NetApp(){
		Logger logger = LogManager.getLogger(NetApp.class);
		logger.error("NET :: LEVEL :: NetApp ERROR Message ::");
	}
}
package net.journaldev;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class NetJournalDevApp {
	public NetJournalDevApp(){
		Logger logger = LogManager.getLogger(NetJournalDevApp.class);
		logger.error("NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::");
	}
}

Enquanto o arquivo de configuração do log4j2 parece abaixo:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>

Se você executar a classe principal, encontrará os resultados abaixo:

10:34:47.168 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
10:34:47.168 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
10:34:47.170 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
10:34:47.170 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
10:34:47.170 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
10:34:47.171 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
10:34:47.171 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
10:34:47.171 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
10:34:47.171 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
10:34:47.171 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

Aqui está a explicação detalhada para o código listado acima:

  • O arquivo de configuração contém cinco instâncias de LoggerConfig definidas e são Root, com, com.journaldev, net e net.journaldev. Assim como a Hierarquia de Registradores mostrada acima.
  • O nível do Root está configurado para ser ERROR e esse é realmente o valor padrão.
  • Os níveis de com e com.journaldev estão configurados para ser TRACE.
  • Os níveis de net e net.journaldev estão configurados para ser ERROR.
  • Você pode ter notado que as mensagens dos loggers ComAPP e ComJournalDevApp foram mostradas duas e três vezes, respectivamente. Essas mensagens são mostradas de acordo com a Hierarquia de Registradores para ComApp e ComJournalDevApp, onde estão nos pacotes com e com.journalDev, respectivamente. Temos caso semelhante com as classes NetApp e NetJournalDevApp.
  • Os pais são propagados, pois o indicador aditivo está configurado como verdadeiro por padrão.

O Espaço de Registro leva em consideração os Níveis dos eventos de registro e o nível do loggerConfig, além da Hierarquia do Logger.

Então, e se nós mudássemos o LoggerConfig para com ser INFO e deixássemos o programa inteiro como está:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="INFO">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>

Então o resultado seria como abaixo:

11:08:10.305 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
11:08:10.305 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
11:08:10.305 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
11:08:10.307 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
11:08:10.307 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
11:08:10.308 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
11:08:10.308 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
11:08:10.308 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
  • Com certeza você pode notar que o evento de log ComAPP foi ignorado e isso ocorre por causa do nível definido pelo loggerConfig para o pacote com. O nível INFO (400) é menor que o nível do evento de log, que aqui é TRACE(600). Portanto, a mensagem de ComApp não será mais mostrada e para mostrá-la, você precisa modificar o nível do LoggerConfig para com para ser TRACE(600) ou ALL(Integer.MAX_VALUE).

Para garantir que os eventos de Log tenham sido exibidos, o Nível do LoggerConfig deve ser maior ou igual ao nível do evento de Log.

A tabela abaixo mostra os Níveis do log4j2 e o peso de cada um deles:

LEVEL Weight
OFF 0
FATAL 100
ERROR 200
WARN 300
INFO 400
DEBUG 500
TRACE 600
ALL Integer.MAX_VALUE

Com certeza a tabela acima esclarece muito mais do que palavras e ela te dá a causa principal para o evento de Log TRACE não ser exibido enquanto o nível do LoggerConfig é INFO.

Observe que a propagação dos eventos de log na hierarquia do logger está além dessa computação e ela ignora os níveis.

Mas o que acontece se removermos o LoggerConfig de com.journaldev da configuração e adicionarmos um novo para com.journaldev.logging para fazer o arquivo de configuração parecer assim:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev.logging" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>

Você pode achar a figura abaixo mais conveniente para entender o que aconteceu na configuração do log4j2 acima. Aqui está uma explicação para a figura mostrada acima e como isso pode afetar o comportamento dos eventos de registro:

  • Quando eventos de registro são lançados por um Logger nomeado com.journaldev.logging, o LoggerConfig associado a esse nome (ou seja, com.journaldev.logging) é usado para lidar com ele e imprimir a mensagem.
  • Como o atributo aditivo do LoggerConfig com.journaldev.logging está definido por padrão como true, o evento de log é propagado para o pai, que neste caso se refere a com.journaldev.
  • Como o LoggerConfig com.journaldev não está definido na configuração, nenhuma ação acontece e o evento de Log será propagado até as instâncias de LoggerConfig de com e então Root.
  • Com e Root receberão o evento de Log e o imprimirão, independentemente do nível com que foi enviado.

Como resultado dos pontos mencionados, você veria as seguintes saídas:

14:08:37.634 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:08:37.634 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:08:37.636 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:08:37.636 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:08:37.637 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:08:37.637 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:08:37.637 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:08:37.638 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:08:37.638 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:08:37.640 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:08:37.640 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:08:37.640 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

E você pode notar o seguinte:

  • O evento de Log no pacote com foi mostrado duas vezes. Uma para com e a segunda para Root.
  • Evento de log em com.journaldev foi mostrado duas vezes. Uma para com e segunda para Root. Mesmo que tenha sido três vezes antes, mas por enquanto o LoggerConfig de com.journaldev está ausente e então nenhum registro pode ter ocorrido no pacote com.journaldev e o evento seria propagado para com e Root.
  • Evento de log em com.journaldev.logging foi mostrado três vezes, uma para o pacote com.journaldev.logging, segunda para com e terceira para Root. De acordo com a propagação da hierarquia de loggers, deveria ser exibido quatro vezes, mas devido à ausência do LoggerConfig de com.journaldev, ele é exibido três vezes.

No caso de você ter definido uma instância LoggerConfig de com.journaldev sem um Nível especificado, ela herdará o Nível de seu pai.

Mas e se você tiver definido o LoggerConfig de com.journaldev em seu arquivo de configuração e esquecido de especificar o nível do LoggerConfig. Felizmente, o conceito de Hierarquia de Loggers irá salvá-lo aqui e com.journaldev herdaria o valor de nível de seu pai. Abaixo está um arquivo de configuração de exemplo seguido pela tabela para o nível de log de cada configuração de logger.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev.logging" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>
Logger Name Assigned LoggerConfig LoggerConfig Level Logger Level
Root Root ERROR ERROR
com com TRACE TRACE
com.journaldev com TRACE TRACE
com.journaldev.logging com.journaldev.logging TRACE TRACE
  • O pacote com.journaldev.logging já está associado a um LoggerConfig com nível de Log TRACE.
  • O pacote com.journaldev já está associado a um LoggerConfig sem nível de Log especificado, então herdaria o Nível de Log do Pai e com certeza o valor seria TRACE para o pacote com.
  • O pacote com já está associado a um LoggerConfig com nível de log TRACE.
  • Por padrão, Root tem ERROR como nível de log.
  • No caso de o pacote com não ser declarado, o LoggerConfig de com.journaldev herdará o nível de log de Root.

Abaixo está o resultado da execução enquanto com.journaldev herda o nível de log com:

14:41:37.419 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:41:37.419 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:41:37.421 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:41:37.421 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:41:37.421 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.423 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:41:37.423 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:41:37.423 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:41:37.423 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:41:37.423 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

E abaixo está o resultado se você remover a declaração LoggerConfig para o pacote com:

14:43:28.809 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:43:28.809 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:43:28.809 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:43:28.811 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:43:28.811 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:43:28.812 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:43:28.812 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:43:28.812 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

Você pode notar que não foram registradas mensagens para com e com.journaldev, abaixo estão os motivos.

  • A exclusão do LoggerConfig associado ao pacote com fará com que todos os eventos de log mencionados nesse pacote sejam ignorados.
  • Já que não há LoggerConfig definido para o pacote com na configuração, o LoggerConfig associado ao com.journaldev herdará o Nível de Log de seu pai. Com não está definido, e a Hierarquia de Log é alcançada até o Topo e agora está se referindo à Raiz. O nível de log raiz é ERROR(200) e o nível de evento de log em com.journaldev é TRACE(600) – Veja ComJournalDevApp – e de acordo com a equação definida anteriormente, o nível do LoggerConfig deve ser maior ou igual ao Evento de Log e isso é falso, então nenhuma mensagem seria exibida aqui para com.journaldev.

Por último, mas não menos importante, a seguir abaixo está a Tabela que mostra todos os cenários possíveis de registro que você pode enfrentar ao usar o sistema de registro:

X (N/A) LoggerConfig Level OFF(0) FATAL(100) ERROR(200) WARN(300) INFO(400) DEBUG(500) TRACE(600) ALL(MAX)
Event Level X X X X X X X X X
OFF(0) X YES NO NO NO NO NO NO NO
FATAL(100) X NO YES YES YES YES YES YES YES
ERROR(200) X NO NO YES YES YES YES YES YES
WARN(300) X NO NO NO YES YES YES YES YES
INFO(400) X NO NO NO NO YES YES YES YES
DEBUG(500) X NO NO NO NO NO YES YES YES
TRACE(600) X NO NO NO NO NO NO YES YES
ALL(MAX) X NO NO NO NO NO NO NO YES
  • Não há um método direto que possa ser usado para lançar eventos de log OFF/ALL.
  • Principalmente, para lançar eventos de log OFF/ALL, você pode usar logger.log(Level.OFF, “Msg”) ou logger.log(LEVEL.ALL,“Msg”), respectivamente.
  • O método de log é responsável por lidar com o evento de log de acordo com a equação mencionada.

A equação de tratamento diz: Se o Nível do LoggerConfig for maior ou igual ao nível do evento de log, o evento será aceito para processamento adicional.

O evento de registro será aceito para processamento adicional – isso é tão importante porque você tem a capacidade de evitar que algum evento seja tratado mesmo que seja aceito usando Filtros do Log4j2. Você pode definir a propriedade additive como false para evitar a propagação do evento de registro para os loggers pai. Seguindo abaixo o mesmo exemplo que você viu antes, mas desta vez com um atributo de aditividade, para que você possa notar a diferença.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="TRACE" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev.logging" level="TRACE" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>

E o resultado da execução seria como abaixo:

17:55:30.558 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
17:55:30.560 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
17:55:30.561 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
17:55:30.561 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
17:55:30.562 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

E você pode notar que não há propagação de eventos de registro para os loggers pai.

Log4j2 Pesquisas

Idealmente, você pode definir pesquisas como uma forma de passar valores para seu arquivo de configuração de Log. O Log4j2 fornece a você um conjunto diferente de Pesquisas que podem ser usadas independentemente para definir valores de diferentes contextos:

  • Pesquisa de Mapa de Contexto
  • Pesquisa de Data
  • Pesquisa de Ambiente
  • Pesquisa Java
  • Pesquisa JNDI
  • Pesquisa de Argumento de Entrada JVM (JMX)
  • Pesquisa de Argumentos Principais
  • Pesquisa de Mapa
  • Pesquisa de Dados Estruturados
  • Pesquisa de Propriedades do Sistema
  • Pesquisa Web

Você pode consultar a documentação do Log4j2 para obter mais detalhes sobre todos os tipos de pesquisas, mas vamos ver alguns exemplos aqui para cobrir o básico da Pesquisa do Log4j2. Pesquisa de Ambiente representa a maneira pela qual você pode passar um valor de ambiente (seja pelo Linux etc/profile, ambiente do sistema Windows ou scripts de inicialização para a aplicação. Como a maioria de nós sabe, temos a capacidade de definir um conjunto de valores ambientais para a aplicação usar. Vamos ver as formas mais famosas de definir suas variáveis ambientais.

  1. Defina a variável de ambiente usando a facilidade de ambiente do Windows:
    • Clique com o botão direito no ícone do seu computador e selecione propriedades. O painel de controle deve ser exibido.
    • Clique em Configurações avançadas do sistema e, em seguida, abra a janela Variáveis de ambiente.
    • No seção Variáveis do sistema, defina a variável JournalDevVar com o valor JournalDev.
    • Atualizando o PatternLayout dentro do seu log4j2.xml para conter sua variável recém-adicionada.

  1. Defina suas variáveis de ambiente usando a facilidade de script de inicialização.
    • Em vez de usar o script padrão normal, você pode usar a facilidade de script em execução do Eclipse IDE, clique no menu Executar e escolha Configuração de Execução.
    • Navegue até a guia Ambiente e defina sua variável lá.

Agora, observe o arquivo log4j2.xml modificado e perceba o uso de variáveis de ambiente.

<Console name="Console" target="SYSTEM_OUT">
    <PatternLayout pattern="%d{HH:mm:ss.SSS} $${env:JournalDevVar} $${env:JournalDevSecondVar} [%t] %-5level %logger{36} - %msg%n"/>
</Console>

E o resultado da execução ficaria assim:

23:57:02.511 JournalDev www.journaldev.com [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
23:57:02.517 JournalDev www.journaldev.com [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
23:57:02.520 JournalDev www.journaldev.com [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
23:57:02.523 JournalDev www.journaldev.com [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
23:57:02.527 JournalDev www.journaldev.com [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

Mas você pode enfrentar um pequeno problema aqui, especialmente ao definir as variáveis de ambiente de um sistema operacional e é o Cache do Eclipse. Idealmente, o Eclipse armazena em cache todas as variáveis de sistema quando é iniciado e você pode encontrá-las em Executar – Configuração de Execução – Aba Ambiente – Clicar no botão Selecionar. Portanto, você pode ficar confuso quando as definiu, mas o Aplicativo não as reconhece. Mesmo se você reiniciar seu Eclipse, não conseguirá a solução e para resolvê-lo você deve executar eclipse.exe -clean na sua instalação do Eclipse. Para garantir que suas variáveis de ambiente estejam definidas corretamente e seu sistema as encontre facilmente, você pode usar o tipo de plugin de correspondência fornecido pela API Log4j2. Crie uma instância de EnvironmentLookup e peça a ela para procurar por uma determinada variável e, se ela estiver definida, você as encontrará facilmente.

EnvironmentLookup lookup = new EnvironmentLookup();
LogManager.getRootLogger().error(lookup.lookup("JournalDevSecondVar"));

Apêndices do Log4j2

Você viu anteriormente como pode usar Lookups para injetar variáveis no seu arquivo de configuração. No entanto, você pode querer modificar o meio pelo qual suas mensagens passam. Em vez de usar o console diretamente, você pode querer usar um arquivo ou um repositório de banco de dados para garantir que suas mensagens sejam retidas permanentemente. O Log4j2 forneceu muitos Appenders e você pode consultar a documentação do log4j2 para obter mais detalhes sobre os Appenders. De maneira resumida, abaixo está a lista de todos os Appenders do Log4j2.

  1. ConsoleAppender
  2. AsyncAppender
  3. FailoverAppender
  4. FileAppender
  5. FlumeAppender
  6. JDBCAppender
  7. JMSAppender
  8. JPAAppender
  9. MemoryMappedFileAppender
  10. NoSQLAppender
  11. OutputStreamAppender
  12. RandomAccessFileAppender
  13. RewriteAppender
  14. RollingFileAppender
  15. RollingRandomAccessFileAppender
  16. RoutingAppender
  17. SMTPAppender
  18. SocketAppender
  19. SyslogAppender

Os meios mais conhecidos usados para registrar eventos são console, arquivo e Banco de Dados. Uma vez que o arquivo salvaria suas mensagens, o banco de dados poderia ser usado para auditoria. Para este propósito, esta seção se concentraria em como o JDBCAppender pode ser usado eficientemente.

JDBCAppender

O principal objetivo do JDBCAppender é escrever eventos de log em uma tabela relacional por meio de conexões JDBC. Não gastamos muito tempo explicando como você pode otimizar seus pools de conexão, pois este tutorial não é destinado a esse fim. Mas com certeza você terá um exemplo completamente funcional que ajuda a escrever seus eventos de log no banco de dados. Antes de prosseguirmos, vamos ver todos os parâmetros necessários e uma descrição de cada um para configurar o JDBCAppender corretamente.

Parameter Name Type Description
Name String Required, The name of the Appender
ignoreExceptions boolean Default value is set to true, making exceptions thrown to be logged also and then ignored. False value means the exception will be propagated for the caller.
filter Filter The filter that should be used to make a decision whether the log events are going to be handled by this Appender or not.
bufferSize int Default value is zero, indicating there’s no buffering have been done upon log events. Value greater than 0 would lead the Appender to buffer log events and then flush them once the buffer reaches the limit specified.
connectionSource ConnectionSource Required, the connections source from which the database connections should be retrieved.
tableName String Required, the name of the Table on which your log events should be persisted.
columnConfigs ColumnConfig[] Required, additional information may be set upon those used columns and how the data should be persisted on each of them. This can be handled with multiple <Column> elements.
Parameter Name Type Description
jndiName String Required, full prefixed JNDI name that the javax.sql.Datasource is bound to.
Parameter Name Type Description
class String Requird, The fully qualified name for a class containg a static factory method for obtaining JDBC connections.
method boolean Required, The name of the static factory method for obtaining JDBC connections.
Parameter Name Type Description
name String Required, the name of the database column
pattern String Ability to specify any legal pattern that Log event would be formatted with
literal String Ability to specify literal value in this column (i.e. SEQ.NEXTVAL)
isEventTimestamp boolean Indicating whether the event would consider Timestamp
isUnicode boolean For unicode purpose as you may refer for Log4j2 documentation for further details
isClob boolean For storing character large object, you may refer for Log4j2 documentation for further details.

Já que você é obrigado a usar JNDI, nosso exemplo configuraria uma fonte de dados de conexão para o banco de dados Oracle e o Apache Tomcat 7.

  • Se você não instalou o banco de dados Oracle em seu ambiente, é apreciado se você puder fazer isso. Se você não conhece muito bem o Oracle, recomendo que instale sua Edição Express.
  • Instale o Apache Tomcat 7 em seu ambiente.
  • Crie um projeto Maven WebApp em seu Eclipse.

  • Verifique se o seu projeto foi criado com sucesso e, se notar algum erro no pom, certifique-se de corrigi-los.
  • Adicione as dependências do Log4j2.
<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>
  • Configure seu contexto para incluir uma declaração de fonte de dados MySQL. De acordo com a documentação do Apache, este arquivo deve estar dentro da pasta META-INF de sua Aplicação Web.

<Context path="/JournalDevWebLogging"
	privileged="true" antiResourceLocking="false" antiJARLocking="false">
	<Resource name="jdbc/JournalDevDB" auth="Container"
			factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
			type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000"
			username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
			url="jdbc:mysql://localhost:3306/journaldev" />
</Context>
  • Configure seu banco de dados e crie sua Tabela de Logs.

CREATE TABLE `logging` (
  `EVENT_ID` int(11) NOT NULL AUTO_INCREMENT,
  `EVENT_DATE` datetime DEFAULT NULL,
  `LEVEL` varchar(45) DEFAULT NULL,
  `LOGGER` varchar(45) DEFAULT NULL,
  `MSG` varchar(45) DEFAULT NULL,
  `THROWABLE` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`EVENT_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
  • Configure o seu log4j2.xml para se parecer com abaixo:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
	<Appenders>
		<Console name="Console" target="SYSTEM_OUT">
			<PatternLayout
				pattern="%d{HH:mm:ss.SSS} $${env:JournalDevVar} $${env:JournalDevSecondVar} [%t] %-5level %logger{36} - %msg%n" />
		</Console>
		<JDBC name="databaseAppender" tableName="journaldev.logging">
			<DataSource jndiName="java:/comp/env/jdbc/JournalDevDB" />
			<Column name="EVENT_DATE" isEventTimestamp="true" />
			<Column name="LEVEL" pattern="%level" />
			<Column name="LOGGER" pattern="%logger" />
			<Column name="MSG" pattern="%message" />
			<Column name="THROWABLE" pattern="%ex{full}" />
		</JDBC>
	</Appenders>
	<Loggers>
		<Root level="ERROR">
			<AppenderRef ref="Console" />
		</Root>
		<logger name="com" level="TRACE" additivity="false">
			<AppenderRef ref="databaseAppender" />
		</logger>
		<logger name="com.journaldev" additivity="false">
			<AppenderRef ref="databaseAppender" />
		</logger>
	</Loggers>
</Configuration>
  • Crie qualquer recurso da Web que permita obter uma referência para um logger e, em seguida, registrar um evento.
package com.journaldev;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class JournalDevServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
			Logger logger = LogManager.getLogger(JournalDevServlet.class);
			logger.trace("JournalDev Database Logging Message !");
	}
}
  • Opcionalmente, você pode configurar um ServletContextListener que garanta que a inicialização da fonte de dados seja feita corretamente.
package com.journaldev;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.logging.log4j.LogManager;
public class JournalDevServletContextListener implements ServletContextListener{
	private InitialContext context = null;
	public void contextDestroyed(ServletContextEvent event) {
	}
	public void contextInitialized(ServletContextEvent event) {
		try {
			// Obtenha o contexto inicial
			context = new InitialContext();
			// Obtenha uma referência para o subcontexto env
			Context envContext = (Context)context.lookup("java:comp/env");
			// Obtenha uma referência para o subcontexto jdbc e depois localize a fonte de dados definida
			LogManager.getRootLogger().error(((Context)envContext.lookup("jdbc")).lookup("JournalDevDB"));
		} catch (NamingException e) {
			LogManager.getRootLogger().error(e);
		}
	}
}
  • Defina seu Servlet dentro do seu arquivo web.xml.
  • Execute a aplicação e acesse o Servlet definido acima. Você verá os logs abaixo.
Mar 15, 2015 2:31:41 PM org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: C:\Program Files\Java\jdk1.6.0_26\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Program Files\Java\jdk1.6.0_26\jre\bin;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/bin/server;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/bin;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/lib/amd64;D:\OracleWebCenter\OracleWC\Oracle11g\app\oracle\product\11.2.0\server\bin;;C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\Program Files (x86)\Common Files\Microsoft Shared\Windows Live;D:\OracleDB\app\product\11.2.0\dbhome_1\bin;org.C:\Program Files (x86)\Common Files\NetSarang;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x86;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x64;D:\SpringRoo\spring-roo-1.2.5.RELEASE\bin;D:\Ant\apache-ant-1.9.2\bin;C:\Python27;C:\Program Files\Java\jdk1.6.0_26\bin;D:\Maven\apache-maven-3.2.1/bin;D:\bower-master\bin;C:\Program Files (x86)\Git\cmd;C:\Program Files\nodejs\;C:\Program Files\Microsoft Windows Performance Toolkit\;D:\Grails\grails-2.4.0\bin;D:\Gradle\gradle-2.0\bin;C:\Program Files (x86)\Windows Live\Shared;C:\Program Files\TortoiseSVN\bin;D:\Strawberry\perl\bin;D:\Strawberry\perl\site\bin;D:\Strawberry\c\bin;C:\Users\mohammad.amr\AppData\Roaming\npm;D:\JournalDev\eclipse;;.
Mar 15, 2015 2:31:41 PM org.apache.tomcat.util.digester.SetPropertiesRule begin
WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.j2ee.server:JournalDevWebLogging' did not find a matching property.
Mar 15, 2015 2:31:41 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-bio-8080"]
Mar 15, 2015 2:31:41 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["ajp-bio-8009"]
Mar 15, 2015 2:31:41 PM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 1020 ms
Mar 15, 2015 2:31:41 PM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Catalina
Mar 15, 2015 2:31:41 PM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.35
14:31:43.847 [localhost-startStop-1] ERROR  - org.apache.tomcat.jdbc.pool.DataSource@10fd0a62{ConnectionPool[defaultAutoCommit=null; defaultReadOnly=null; defaultTransactionIsolation=-1; defaultCatalog=null; driverClassName=com.mysql.jdbc.Driver; maxActive=100; maxIdle=30; minIdle=10; initialSize=10; maxWait=10000; testOnBorrow=false; testOnReturn=false; timeBetweenEvictionRunsMillis=5000; numTestsPerEvictionRun=0; minEvictableIdleTimeMillis=60000; testWhileIdle=false; testOnConnect=false; password=root; url=jdbc:mysql://localhost:3306/journaldev; username=root; validationQuery=null; validatorClassName=null; validationInterval=30000; accessToUnderlyingConnectionAllowed=true; removeAbandoned=false; removeAbandonedTimeout=60; logAbandoned=false; connectionProperties=null; initSQL=null; jdbcInterceptors=null; jmxEnabled=true; fairQueue=true; useEquals=true; abandonWhenPercentageFull=0; maxAge=0; useLock=false; dataSource=null; dataSourceJNDI=null; suspectTimeout=0; alternateUsernameAllowed=false; commitOnReturn=false; rollbackOnReturn=false; useDisposableConnectionFacade=true; logValidationErrors=false; propagateInterruptState=false; }
Mar 15, 2015 2:31:43 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8080"]
Mar 15, 2015 2:31:43 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-bio-8009"]
Mar 15, 2015 2:31:43 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 1909 ms

Filtros do Log4j2

Mesmo que haja um candidato LoggerConfig para lidar com o evento de Log, você pode configurá-lo para negar a passagem dos eventos de Log para os Appenders de backend. Isso pode ser feito por meio de um filtro log4j2. Esta seção não se destina a fornecer um tutorial invasivo, massivo e enorme sobre o uso de filtros no Log4j2, pois eles precisam de muitos artigos cobrindo cada um deles. Mas aqui, você verá como usar o filtro mais simples para aprender o conceito. Um dos filtros mais simples que você pode usar é o BurstFilter, que fornece um mecanismo para controlar a taxa na qual os LogEvents são processados descartando silenciosamente eventos após o limite máximo ter sido atingido. Por enquanto, você pode ver abaixo todos os detalhes necessários para usar o BurstFilter.

Parameter Name Type Description
level String Level of messages to be filtered
rate float The average number of events per second to allow
maxBurst integer The maximum number of events that can occur before events are filtered for exceeding the average rate. The default is 10 times the rate.
onMatch String Action to take when filter matches. May be Accept, DENY or NEUTRAL. The default is NEUTRAL
onMismatch String Action to tale when filter doesn’t match. May be Accept, DENY or NEUTRAL. The default is NEUTRAL

Agora, observe a localização do BurstFilter dentro do seu Appender de banco de dados.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
	<Appenders>
		<Console name="Console" target="SYSTEM_OUT">
			<PatternLayout
				pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
		</Console>
		<JDBC name="databaseAppender" tableName="journaldev.logging">
			<DataSource jndiName="java:/comp/env/jdbc/JournalDevDB" />
			<BurstFilter level="TRACE" rate="20" maxBurst="2"/>
			<Column name="EVENT_DATE" isEventTimestamp="true" />
			<Column name="LEVEL" pattern="%level" />
			<Column name="LOGGER" pattern="%logger" />
			<Column name="MSG" pattern="%message" />
			<Column name="THROWABLE" pattern="%ex{full}" />
		</JDBC>
	</Appenders>
	<Loggers>
		<Root level="ERROR">
			<AppenderRef ref="Console" />
		</Root>
		<logger name="com" level="TRACE" additivity="false">
			<AppenderRef ref="databaseAppender" />
		</logger>
		<logger name="com.journaldev" additivity="false">
			<AppenderRef ref="databaseAppender" />
		</logger>
	</Loggers>
</Configuration>
  • O Appender do banco de dados considera o BurstFilter, enquanto o Appender de console não o faz.
  • Ao usar o console, você terá todos os eventos de log registrados, mas o Appender do banco de dados não fará isso, pois o BurstFilter negará que alguns deles prossigam.
  • Essa negação de LogEvents é alcançada mesmo quando os Loggers usados são candidatos para lidar com os LogEvents. Isso é muito razoável, como mostrado no JournalDevServlet abaixo.

package com.journaldev;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class JournalDevServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
		Logger logger = LogManager.getLogger(JournalDevServlet.class);
		for(int i = 0 ; i < 1000 ; i++){
			logger.trace("Index :: "+i+" :: JournalDev Database Logging Message !");
			LogManager.getRootLogger().error("Index :: "+i+" :: JournalDev Database Logging Message !");
		}
	}
}

Mesmo que essas LoggerConfigs sejam candidatas para lidar com os Log Events lançados lá, o Filtro impediu que alguns deles fossem manipulados e, em seguida, registrados. Você pode adicionar isso ao conceito de Logging Space para entender o conceito completo de logging.

Layouts do Log4j2

Devido aos diferentes Apêndices que consomem Eventos de Log e à natureza de cada apêndice, os layouts são feitos para formar o Evento de Log no formato que atenda às necessidades de quem irá consumir o evento de log. Nas APIs Log4j 1.x e Logback, a transformação do layout dos Eventos de Log era em uma String, enquanto os layouts do Log4j2 consideraram uma forma diferente de transformação; e isso é feito transformando o Evento de Log em uma matriz de bytes. Esse novo tipo de transformação exigiria que você configurasse o Charset para garantir que a matriz de bytes contenha os valores corretos. É altamente recomendável retornar ao site oficial do Apache Log4j2 e ver mais sobre Layout e os diferentes tipos que o Log4j2 fornece. Nesta seção, consideraremos o layout mais famoso que é sempre usado pela maioria de nossos desenvolvedores e com certeza você pode ter ouvido falar sobre ele; é o PatternLayout.

Log4j2 PatternLayout

O layout de padrão é um padrão configurável e flexível de String destinado a formatar o LogEvent. Esse tipo de formatação depende do conceito de padrão de conversão. Esta seção irá mostrar as características mais importantes que o layout de padrão oferece. O padrão de conversão está relacionado ao padrão de conversão fornecido pelo printf na linguagem C. Geralmente, o padrão de conversão é composto por texto literal e expressões de controle de formato chamadas especificadores de conversão. A figura abaixo mostra de quais partes o padrão de conversão é composto: Esta figura acima é uma tentativa de simplificar o Padrão de Conversão, mas é melhor consultar a documentação do Apache Log4j2 para obter mais detalhes sobre Layouts e Especificamente Padrão de Layout. Além disso, você pode consultar acima para eventos de log e ver a cada momento qual Padrão de Conversão está sendo usado para formatar as mensagens.

Qual nível de Log4j2 você deve usar

A maior questão que você pode se perguntar é quando um nível específico de evento de log deve ser usado. No campo de desenvolvimento, é normal usar o evento de log DEBUG, enquanto em produção devemos usar o nível INFO ou WARN. A tabela abaixo deve orientá-lo sobre qual nível de log4j2 deve ser usado em cada caso.

Log Event Level When It Should Be Used
OFF When no events will be logged
FATAL When a severe error will prevent the application from continuing
ERROR When an error in the application, possibly recoverable
WARN When an event that might possible lead to an error
INFO When an event for informational purposes
DEBUG When a general debugging event required
TRACE When a fine grained debug message, typically capturing the flow through the application
ALL When all events should be logged

Resumo do Tutorial do Log4j2

O Log4j2 é a versão renovada do framework de log do Apache. O Log4j2 oferece um conjunto de novos recursos e melhorias de desempenho em relação ao Log4j1.x. Este tutorial do log4j2 tem como objetivo ajudá-lo a obter tudo em um só lugar. Como alguns desses conceitos não são tão fáceis de serem abordados de uma só vez, decidimos concentrar nossos esforços em explicar o conceito e usar alguns exemplos para maior esclarecimento. Aplicativos, filtros, layouts e pesquisas estão sujeitos a essa regra. Alguns pontos importantes Para garantir que você seja capaz de executar o aplicativo abaixo e evitar quaisquer obstáculos, verifique o seguinte:

  • O seu IDE Eclipse está habilitado para o Maven.
  • O seu Apache Tomcat tem um JAR do mysql-connector dentro da pasta lib do seu diretório Apache Home.
  • Você sabe como usar o Maven.

Baixe o Projeto de Exemplo do Apache Log4j 2

Isso é tudo para o tutorial do log4j2. Espero que a maioria dos pontos importantes esteja coberta para ajudá-lo a começar a usar o Log4j2 em seu aplicativo.

Source:
https://www.digitalocean.com/community/tutorials/log4j2-example-tutorial-configuration-levels-appenders