Loggin de Eventos com Log4J

por Luiz Gustavo Stábile de Souza

versão em pdf

O que é logging?

Fazer o logging de uma aplicação é uma das possíveis maneiras de debugá-la, registrando em algum meio (arquivo, enviando e-mails, gravando em bancos de dados, etc..) eventos ocorridos na aplicação, sejam eles apenas informações, ou indicações de erros no processamento.

O framework de logging Log4J

O Log4j é uma ferramenta open-source de logging, desenvolvida sob o projeto Apache Jakarta. É um conjunto de APIs que permite aos desenvolvedores escreverem declarações de log em seus códigos e configurá-los externamente, através de arquivos de propriedades.

Para usarmos o Log4J, precisamos entender três aspectos deste framework: logger, appender, e layout. Entenda a relação dos três como a seguinte:

Um logger envia os logs para um appender, que os armazena em um determinado layout (estilo).

Logger

Pense em um logger como um componente silencioso em sua aplicação, responsável por receber requisições de log e efetuá-las.

Cada classe de uma aplicação pode ter um logger individual, mas o framework Log4J oferece um logger padrão. Caso você não crie um logger específico, pode usar o logger padrão oferecido pelo framework, chamando o método estático getRootLogger() da classe Logger.

Appender

Loggers precisam saber para onde enviar as informações de log. É aqui que os appenders entram em cena. O framework Log4J suporta o envio de informações de log para arquivos (FileAppender), para o console (ConsoleAppender) , para bancos de dados (JDBCAppender) , para eventos de log de sistemas NT (NTEventLogAppender) , para servidores SMTP (SMTPAppender), para servidores remotos (SocketAppender) , e outros.

Um appender define as propriedades do destino de log para o Log4J. Desta maneira, se nós associarmos um appender do tipo JDBCAppender a um logger, estamos dizendo ao Log4J que os logs passados a este logger devem ser armazenados em uma determinada base de dados. Todas essas informações, referentes a como acessar o meio de armazenamento são propriedades do appender, e são usadas pelo Log4J para saber onde armazenar as informações.

Layout

Loggers e appenders estão relacionados a criação e redirecionamento de nossas solicitações de log. E quanto ao formato em que serão armazenadas essas informações de log?

Isso é o papel do layout, que define o estilo e o conteúdo da informação de log. Um layout define, por exemplo quando incluir informações de data e hora nos logs, linha onde o log se originou, etc.

Relação de herança entre loggers

Existe no Log4J uma relação de “pai e filho” entre os loggers que criamos. Essa relação é definida através de um padrão de nome, com a utilização do operador ponto “.”.

Como citado anteriormente, pelo menos um logger existe para uma aplicação, o logger padrão oferecido pelo framework, e em último caso todos os loggers que criamos são filhos deste logger padrão.

Para ilustrar essa relação de pai e filho entre os loggers, imagine que temos um logger cujo nome é br.com.meulogger.MyLog, definido para uma classe de mesmo nome e mesmo pacote. Este logger será automaticamente “filho” de um logger que tenha o nome br.com.meulogger, caso ele exista, pelo simples fato de o nome do último fazer parte do nome do primeiro.

Níveis de logging no Log4J

Todo logger que usamos possui um, de cinco possíveis níveis definidos pelo Log4J: DEBUG, INFO, WARN, ERROR e FATAL. Se esse nível não for configurado explicitamente para um logger, será herdado de um logger “pai”, que em último caso pode ser o logger padrão, definido pelo framework, e que possui um nível DEBUG. Portanto, todos os loggers em uma aplicação terão, no mínimo, o nível DEBUG.

Mas para que servem estes níveis, e como eles podem afetar o mecanismo de logging?

Assim como os loggers, todas as requisições de logging feitas a eles também possuem um nível. As requisições de logging somente serão atendidas se o seu nível for maior ou no mínimo igual ao nível do logger.

Por exemplo, suponha que tenho um logger com o nível definido para WARN. Se uma solicitação de logging, de nível INFO chegar a ele, ela não será atendida, e portanto não será registrada no appender relacionado ao logger.

Se enviarmos, para este mesmo logger, uma solicitação de logging de nível ERROR, ou WARN, ela será atendida e registrada, pois possui um nível maior ou pelo menos igual ao nível do logger.

Essa característica é muito importante, pois podemos modificar externamente (através de arquivos de configuração) o nível dos loggers de nossa aplicação, sem ter que alterar o código. Isso permite habilitar um nível DEBUG durante o desenvolvimento, mas deixar somente o nível ERROR habilitado em produção.

Uma aplicação de exemplo

Para este exemplo vou utilizar o Eclipse IDE, mas se você preferir, pode executá-lo em outro IDE de sua preferência. Crie um pojeto Java simples, conforme mostra a figura 1:

figura 1: criação de um projeto Java simples

Crie para o seu projeto um pacote com o nome de sua preferência, e nele crie uma classe chamada ExemploLog4J:

figura 2: criação da classe ExemploLog4J.java

Em seguida, digite o seguinte código para a classe ExemploLog4J (se for necessário, faça as adaptações pra o nome do seu pacote, se ele for diferente):


package blogspot.luizgustavoss.log4j;

import javax.swing.JOptionPane;

public class ExemploLog4J {

    public static void main(String[] a) {

        ExemploLog4J exemplo = new ExemploLog4J();

        exemplo.run();

    }

    public void run() {

        int quantidade = solicitarQuantidade();
        int[] valores = new int[quantidade];
        lerValoresInteiros(valores);
        double resultado = calcularMedia(valores);
        exibirValorReal(resultado);
    }

    public void exibirValorReal(double valor) {

        JOptionPane.showMessageDialog(null, "o valor é: " + valor);

    }

    public double calcularMedia(int[] v1) {

        double soma = 0;
        int total = 0;
        double resultado = 0;

        try {

            for (int i : v1) {

                total++;
                soma += i;

            }
            resultado = (soma / total);

        } catch (Exception e) {
            System.out.println("Erro!");
        }

        return resultado;
    }

    public int solicitarQuantidade() {

        int valor = 0;

        try {

            valor = Integer.parseInt(JOptionPane.showInputDialog("Quantos valores?:"));

        } catch (Exception e) {

            System.out.println("Erro!");

        }

        return valor;

    }

    public void lerValoresInteiros(int[] valores) {

        try {

            for (int i = 0; i< valores.length ; i++){

                valores&#91;i&#93; = Integer.parseInt(JOptionPane.showInputDialog("valor:"));

            }

        } catch (Exception e) {

            System.out.println("Erro!");
        }

    }
}

&#91;/sourcecode&#93;
<p class="western" style="margin-bottom:0;" align="justify"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;">Repare que para os possíveis casos de exceção estamos  apenas enviando a mensagem <em>"Erro!"</em> para o console, como forma de registrar o erro. Logo modificaremos este comportamento. Agora vamos configurar o framework Log4J para nossa aplicação.</span></span></p>
<p class="western" style="margin-bottom:0;" align="justify"></p>
<p class="western" style="margin-bottom:0;" align="justify"></p>
<p class="western" style="margin-bottom:0;" align="justify"></p>
<p class="western" style="margin-bottom:0;" align="justify"></p>
<p class="western" style="border:medium none;margin-bottom:0;padding:0;" align="justify"><span style="color:#ff6309;"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;"><strong>Configurando o Log4J</strong></span></span></span></p>
<p class="western" style="margin-bottom:0;" align="justify"></p>
<p class="western" style="margin-bottom:0;" align="justify"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;">O primeiro passo para a configuração do Log4J é adicionar o seu arquivo <em>.jar</em> em nosso projeto. Para isso clique com o botão direito do mouse sobre o projeto e escolha a opção <em>Properties.</em><span style="font-style:normal;"> Em seguida escolha a aba </span><em>Libraries</em><span style="font-style:normal;">, conforme mostra a figura 3:</span></span></span></p>
<p style="text-align:center;"><a href="https://luizgustavoss.files.wordpress.com/2008/04/log4j_tela3.png"><img class="alignnone size-medium wp-image-9" src="https://luizgustavoss.files.wordpress.com/2008/04/log4j_tela3.png?w=400" alt="" width="400" height="315" /></a></p>
<p class="western" style="margin-bottom:0;" align="center"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;"><em>figura 3: tela para adição de bibliotecas ao projeto</em></span></span></p>
<p class="western" style="margin-bottom:0;" align="justify"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;"><span style="font-size:medium;">Nesta tela, clique no botão <em>Add External jARs</em>, e informe o arquivo <em>.jar</em> do Log4J, que pode ser encontrado no site oficial do projeto (</span><a href="http://logging.apache.org/log4j/"><span style="font-size:medium;"><span style="font-family:Times New Roman,serif;">http://logging.apache.org/log4j/)</span></span></a><span style="font-size:medium;"><span style="font-family:Times New Roman,serif;">, na seção de downloads.</span></span></span></span></p>
<p class="western" style="margin-bottom:0;" align="justify"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;">Depois de adicionado o arquivo .jar, a tela deverá estar como apresentado na figura 4:</span></span></p>
<p style="text-align:center;"><a href="https://luizgustavoss.files.wordpress.com/2008/04/log4j_tela41.png"><img class="aligncenter size-medium wp-image-11" src="https://luizgustavoss.files.wordpress.com/2008/04/log4j_tela41.png?w=400" alt="" width="400" height="315" /></a></p>
<p class="western" style="margin-bottom:0;" align="center"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;"><em>figura 4: tela para adição de bibliotecas ao projeto depois de adicionar o jar do Log4J</em></span></span></p>
<p class="western" style="margin-bottom:0;" align="justify"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;">Como foi dito anteriormente, a configuração do Log4J pode ser feita externamente, através de arquivos de configuração, e pode ser feita também programaticamente, através de código. Para este estudo, vamos focar na configuração do Log4J através de arquivos de configuração, por ser uma abordagem mais flexível do que a configuração programática.</span></span></p>
<p class="western" style="margin-bottom:0;" align="justify"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;">O arquivo de configuração do Log4J é um arquivo de texto simples, do tipo <em>properties</em>, cujo conteúdo é um conjunto de chaves-valores associados. O nome do arquivo é, por padrão, <em>log4j.properties</em>. Crie um arquivo com este nome<span style="font-style:normal;"> na raiz do projeto. Para isso, no Eclipse, clique sobre o nome do projeto e escolha no menu a opção </span><em>New&gt;Other&gt;General&gt;File</em><span style="font-style:normal;">:</span></span></span></p>
<p style="text-align:center;"><a href="https://luizgustavoss.files.wordpress.com/2008/04/log4j_tela5.png"><img class="alignnone size-medium wp-image-12" src="https://luizgustavoss.files.wordpress.com/2008/04/log4j_tela5.png" alt="" width="251" height="300" /></a></p>
<p class="western" style="margin-bottom:0;" align="center"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;"><em>figura 5: criação do arquivo log4j.properties</em></span></span></p>
<p class="western" style="margin-bottom:0;" align="justify"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;">Logo após a criação do arquivo, a estrutura do projeto deve estar parecida com a apresentada na figura 6:</span></span></p>
<p style="text-align:center;"><a href="https://luizgustavoss.files.wordpress.com/2008/04/log4j_tela6.png"><img class="aligncenter size-medium wp-image-13" src="https://luizgustavoss.files.wordpress.com/2008/04/log4j_tela6.png?w=400" alt="" width="400" height="300" /></a></p>
<p class="western" style="margin-bottom:0;" align="center"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;"><em>figura 6: projeto já com o arquivo log4j.properties</em></span></span></p>
<p class="western" style="margin-bottom:0;" align="justify"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;">A seguir está o conteúdo para o arquivo log4j.properties. Os comentários explicam a função de cada linha:</span></span></p>
<p class="western" style="margin-bottom:0;" align="justify"></p>



# Configura dois appenders (stdout para o console, fileout para um arquivo)
# para o logger padrão, e configura um nível (INFO). Como todos os
# loggers que criamos herdam do logger padrãoo, quaisquer loggers que criarmos
# terão esta configuração
log4j.rootCategory=INFO, stdout, fileout
# O primeiro appender escreve para o console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
# O padrão para apresentação do conteúdo (layout)
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
# O segundo appender escreve para um arquivo
log4j.appender.fileout=org.apache.log4j.RollingFileAppender
log4j.appender.fileout.File=exemplo.log
# Controla o tamanho máximo do arquivo de log
log4j.appender.fileout.MaxFileSize=500KB
# Arquiva arquivos de log (somente um arquivo de backup)
log4j.appender.fileout.MaxBackupIndex=1
# O padrãoo para apresentação do conteúdo (layout)
log4j.appender.fileout.layout=org.apache.log4j.PatternLayout
log4j.appender.fileout.layout.ConversionPattern=(%F:%L) %p %t %c - %m%n

Agora que temos o framework devidamente configurado, vamos alterar nossa classe para que sejam efetuados os logs. Adicione a seguinte declaração à classe ExemploLog4J:


private org.apache.log4j.Logger logger = Logger.getLogger( ExemploLog4J.class.getName() );

O que esta declaração faz é criar um logger, com o mesmo nome da nossa classe. Agora, outras solicitações de logging são adicionadas ao código, inclusive substituindo o que foi colocado nos blocos catch. Eis o código final:


package blogspot.luizgustavoss.log4j;

import javax.swing.JOptionPane;
import org.apache.log4j.Logger;

public class ExemploLog4J {

    private org.apache.log4j.Logger logger = Logger.getLogger(ExemploLog4J.class.getName());

    public static void main(String[] a) {

        ExemploLog4J exemplo = new ExemploLog4J();
        exemplo.run();
    }

    public void run() {

        logger.info("Iniciando o método run...");
        int quantidade = solicitarQuantidade();
        int[] valores = new int[quantidade];
        lerValoresInteiros(valores);
        double resultado = calcularMedia(valores);
        exibirValorReal(resultado);
        logger.info("Método o run finalizado!");

    }

    public void exibirValorReal(double valor) {

        JOptionPane.showMessageDialog(null, "o valor é: " + valor);
        logger.info("Operaçãoo exibirValorReal realizada!");

    }

    public double calcularMedia(int[] v1) {

        double soma = 0;
        int total = 0;
        double resultado = 0;

        try {

            for (int i : v1) {

                total++;
                soma += i;
            }

            resultado = (soma / total);
            logger.info("Operação calcularMedia realizada!");

        } catch (Exception e) {

            logger.error("Erro na operação calcularMedia!");
        }

        return resultado;

    }

    public int solicitarQuantidade() {

        int valor = 0;

        try {

            valor = Integer.parseInt(JOptionPane.showInputDialog("Quantos valores?:"));
            logger.info("Operação solicitarQuantidade realizada!");

        } catch (Exception e) {

            logger.error("Erro na operação solicitarQuantidade!");
        }

        return valor;
    }

    public void lerValoresInteiros(int[] valores) {

        try {

            for (int i = 0; i < valores.length; i++) {

                valores&#91;i&#93; = Integer.parseInt(JOptionPane.showInputDialog("valor:"));
            }

            logger.info("Operação lerValoresInteiros realizada!");

        } catch (Exception e) {

            logger.error("Erro na operação lerValoresInteiros!");
        }

    }
}

&#91;/sourcecode&#93;
<p class="western" style="margin-bottom:0;" align="justify"></p>
<p class="western" style="margin-bottom:0;" align="justify"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;">Repare nas chamadas a <em>info</em> e <em>error</em> no logger criado. Estas são solicitações de logging nos níveis INFO e ERROR respectivamente, ou seja, para cada nível de logging há um método correspondente que pode ser chamado em um logger.</span></span></p>
<p class="western" style="margin-bottom:0;" align="justify"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;">Agora vamos executar o projeto e ver qual o resultado para as configurações feitas até o momento. Clique no botão Run e escolha a opção de executar como uma aplicação Java comum:</span></span></p>
<p style="text-align:center;"><a href="https://luizgustavoss.files.wordpress.com/2008/04/log4j_tela7.png"><img class="alignnone size-medium wp-image-14" src="https://luizgustavoss.files.wordpress.com/2008/04/log4j_tela7.png" alt="" width="298" height="300" /></a></p>
<p class="western" style="margin-bottom:0;" align="center"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;"><em>figura 7: execução do programa</em></span></span></p>
<p class="western" style="margin-bottom:0;font-style:normal;" align="justify"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;">Repare que todas as solicitações de logging foram atendidas por nosso logger, conforme mostra a figura 8, pois ele está configurado, de acordo com o arquivo de configuração, para atender a solicitações a partir do nível INFO.</span></span></p>
<p style="text-align:center;"><a href="https://luizgustavoss.files.wordpress.com/2008/04/log4j_tela8.png"><img class="alignnone size-medium wp-image-15" src="https://luizgustavoss.files.wordpress.com/2008/04/log4j_tela8.png?w=400" alt="" width="400" height="300" /></a></p>
<p class="western" style="margin-bottom:0;" align="center"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;"><em>figura 8: execução das solicitações de logging</em></span></span></p>
<p class="western" style="margin-bottom:0;font-style:normal;" align="justify"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;">Sem modificar nosso código, vamos alterar o nível de INFO para WARN, no arquivo log4j.properties:</span></span></p>
<p style="text-align:center;"><a href="https://luizgustavoss.files.wordpress.com/2008/04/log4j_tela9.png"><img class="alignnone size-medium wp-image-16" src="https://luizgustavoss.files.wordpress.com/2008/04/log4j_tela9.png?w=400" alt="" width="400" height="300" /></a></p>
<p class="western" style="margin-bottom:0;" align="center"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;"><em>figura 9: configuração do nível de logging para WARN</em></span></span></p>
<p class="western" style="margin-bottom:0;font-style:normal;" align="justify"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;">Repare também, na imagem acima, que foi criado um arquivo chamado <em>exemplo.log</em>, conforme indicado no arquivo de configurações.</span></span></p>
<p class="western" style="margin-bottom:0;font-style:normal;" align="justify"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;">Agora execute a aplicação e informe uma letra, ao invés de um número, para o primeiro painel que surge. Você verá que as solicitações de logging com nível <em>INFO</em> – feitas através do método <em>info</em> – não são atendidas, somente a solicitação de nível <em>ERROR</em>, conforme mostra a figura 10.</span></span></p>
<p style="text-align:center;"><a href="https://luizgustavoss.files.wordpress.com/2008/04/log4j_tela10.png"><img class="alignnone size-medium wp-image-17" src="https://luizgustavoss.files.wordpress.com/2008/04/log4j_tela10.png?w=400" alt="" width="400" height="300" /></a></p>
<p class="western" style="margin-bottom:0;" align="center"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;"><em>figura 10: é efetuado somente o logging de nível ERROR</em></span></span></p>
<p class="western" style="margin-bottom:0;font-style:normal;" align="justify"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;">Esta facilidade de configuração nos permite adicionar solicitações de logging em tempo de projeto, que podem, em tempo de produção, ser desabilitadas.</span></span></p>
<p class="western" style="margin-bottom:0;font-style:normal;" align="justify"><span style="font-family:Times New Roman,serif;"><span style="font-size:medium;">Para evitar um processamento desnecessário, podemos ainda realizar um teste antes da solicitação de um logging, checando o nível de logging habilitado para o logger:</span></span></p>
<p class="western" style="margin-bottom:0;font-style:normal;" align="justify"></p>



if (logger.isInfoEnabled()) {

    logger.info("Informação!");

}

Conclusão

A utilização de logging em aplicações é de extrema importância, uma vez que durante o desenvolvimento ajuda no debbug, e em produção permite registrar eventos importantes ao longo da execução e rastrear problemas ocorridos.

Este tutorial teve o objetivo de apresentar o framework Log4J, que é uma das principais alternativas dentre os frameworks de logging disponíveis. Foram apresentadas suas principais características, uma das formas de configuração, e sua utilização em uma aplicação prática.

Referências

Apache Log4j
http://logging.apache.org/log4j/

Goyal, Vikram – Build Flexible Logs With log4j
http://www.onjava.com/pub/a/onjava/2002/08/07/log4j.html

13 comentários sobre “Loggin de Eventos com Log4J

  1. Olá amigo. desculpa pelo comentário anterior incompleto.

    Segui o tutorial a risca e me deparei com estas mensagens de erro:

    log4j:WARN No appenders could be found for logger (george.Log4jTeste).
    log4j:WARN Please initialize the log4j system properly.

  2. Já resolvi o problema.

    Para fins de pesquisa irei colocar a solução:

    Coloquei o arquivo log4j.properties dentro de uma pasta chamada LIB e a adicionei esta pasta ao BUILD PATH do meu projeto (No package Explorer, clico com o botão direito no meu Projeto, depois seleciono BUILD PATH e depois Configure Build Path. Na janela que se abre, seleciono a ABA SOURCE e clico no botão “Add Folder”. Localizo a pasta LIB que eu tinha criado e mandei o projeto rodar novamente! e ok).

    amigo, obrigado pelo tutorial. Já o salvei para meu computador.

    Estou precisando de um tutorial assim como o seu, super explicado para iniciantes, sobre Hibernate. Você pode me sugerir algum?

    Um forte abraço e fique com Deus.

  3. Olá George, tudo bem?
    Primeiramente obrigado pelos comentários, e por visitar o blog.
    Espero que o tutorial tenha sido útil.
    Quanto ao tutorial de Hibernate, vou tomar como uma sugestão a criação de tal tutorial, mas por hora posso te indicar o seguinte:

    http://www.guj.com.br/java.tutorial.artigo.174.1.guj

    Pena que ele não aborde, ainda, a utilização de anotações, mas é de grande ajuda para quem estácomeçando.

    Abraços!

  4. Pingback: Logging e Log4j
  5. Olá, Luiz Gustavo,

    Gostaria de agradecer pelo tutorial, estava sofrendo MUITO para conseguir fazer isso funcionar corretamente. Por fim meu arquivo de propriedades estava incorreto, utilizando e observando os comentários do seu, consegui contornar o problema.

    Obrigado por compartilhar conhecimento com qualidade.

    Abraço.

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s