1. Por que precisamos de logging
Logging ≠ saída no console
Quando você está começando a programar, parece que para encontrar problemas basta colocar System.out.println("Estive aqui!") em todo lugar. Isso funciona enquanto o programa é pequeno e roda no seu computador. Mas imagine um projeto grande, um servidor que fica no ar 24/7, ou um aplicativo usado por milhares de pessoas — você não vai ficar atrás de cada usuário olhando o console dele, certo?
Logging — não é apenas imprimir mensagens. É o registro sistematizado de informações sobre o funcionamento do aplicativo: erros, avisos, eventos de negócio, detalhes técnicos. Os logs são salvos em arquivos, bancos de dados, podem ser enviados pela rede — e permitem analisar o comportamento do programa após a execução ou em tempo real.
Para que servem os logs
- Diagnóstico de problemas: se algo deu errado, os logs são seu principal aliado. Com eles é possível entender onde e por que o erro ocorreu.
- Auditoria e segurança: os logs registram ações importantes dos usuários, o que ajuda a investigar incidentes.
- Depuração: às vezes os bugs aparecem apenas em certas condições, e sem logs é impossível capturá-los.
- Monitoramento: pelos logs é possível acompanhar o estado do aplicativo, seu desempenho e a sua “saúde”.
Exemplo da vida real
Se os aviões não tivessem “caixas-pretas” (logs de voo), investigar as causas de acidentes seria quase impossível. Em programação, os logs são as suas caixas-pretas.
2. Níveis básicos de logging
No logging é comum usar níveis (levels) de mensagens. É como um semáforo: vermelho — perigoso, amarelo — atenção, verde — tudo certo.
Níveis principais (do mais “barulhento” ao mais “silencioso”):
| Nível | Descrição |
|---|---|
|
Erro crítico, o aplicativo não pode continuar a execução |
|
Aviso: algo saiu errado, mas o programa continua funcionando |
|
Mensagem informativa sobre eventos normais |
|
Informações detalhadas para depuração (visível apenas para desenvolvedores) |
|
Informação mais detalhada — para diagnóstico profundo |
Exemplo:
- O usuário não conseguiu entrar por senha incorreta — isso é WARN.
- Falha no banco de dados — isso é ERROR.
- O aplicativo iniciou — isso é INFO.
- Imprimir o valor de uma variável em um loop — isso é DEBUG ou TRACE.
Como escolher o nível
Não escreva tudo no nível ERROR — caso contrário, você vai se afogar entre os erros reais. Use os níveis com consciência: apenas falhas realmente críticas devem ser erros.
3. Logging padrão no Java (java.util.logging)
O Java vem com um sistema de logging embutido — o pacote java.util.logging (abreviado como JUL). É a ferramenta “nativa”, sempre disponível mesmo que você não adicione nenhuma biblioteca.
Classes principais:
- Logger — a classe principal para gravar logs.
- Level — enumeração dos níveis de logging (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST).
- Handler — um handler que indica para onde escrever os logs (arquivo, console etc.).
- Formatter — responsável pelo formato das mensagens.
Exemplo de uso do JUL
import java.util.logging.Logger;
import java.util.logging.Level;
public class LoggingExample {
// Obtemos o logger pelo nome da classe
private static final Logger logger = Logger.getLogger(LoggingExample.class.getName());
public static void main(String[] args) {
logger.info("Aplicativo iniciado");
logger.warning("Isto é um aviso!");
logger.severe("E isto já é um erro!");
int x = 42;
logger.fine("Variável de depuração x=" + x); // Não é exibido por padrão
}
}
Ponto importante: por padrão, o JUL exibe apenas os níveis INFO e superiores. Para ver fine e outras mensagens detalhadas, é preciso configurar o nível de logging.
Configuração via arquivo
Você pode configurar o JUL pelo arquivo logging.properties (geralmente na pasta da JRE). Lá é possível definir:
- O nível mínimo para o logger
- Para onde escrever os logs (arquivo, console)
- O formato das mensagens
Exemplo de linha em logging.properties:
.level=INFO
4. Bibliotecas externas de logging
Log4j (Apache)
Log4j é uma das bibliotecas de logging mais conhecidas para Java. É flexível, poderosa, suporta diferentes formatos, gravação assíncrona, rotação de arquivos e muito mais.
Exemplo de configuração mais simples do Log4j 2 (XML):
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
Exemplo de uso do Log4j 2 no código:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4jExample {
private static final Logger logger = LogManager.getLogger(Log4jExample.class);
public static void main(String[] args) {
logger.info("Hello from Log4j!");
logger.error("Este é um erro via Log4j");
}
}
Para isso funcionar, é preciso adicionar as dependências do Log4j ao seu projeto (por exemplo, via Maven ou Gradle).
SLF4J: fachada de logging
SLF4J (Simple Logging Facade for Java) não é um sistema de logging separado, mas sim uma “camada” entre o seu código e uma implementação específica (Log4j, Logback, JUL etc.).
A fachada existe para que você escreva o código uma vez e, se necessário, troque o sistema de logging real sem reescrever o código, mesmo que bibliotecas diferentes usem loggers diferentes.
Exemplo de uso do SLF4J:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Slf4jExample {
private static final Logger logger = LoggerFactory.getLogger(Slf4jExample.class);
public static void main(String[] args) {
logger.info("Olá, logging via SLF4J!");
logger.warn("Atenção: algo pode dar errado");
logger.error("Erro via SLF4J");
}
}
Como isso funciona?
- Você escreve o código via SLF4J.
- No classpath você adiciona a implementação desejada (por exemplo, Logback ou Log4j).
- SLF4J encaminha as chamadas para a implementação escolhida.
Integração do SLF4J com outros loggers: o SLF4J pode operar sobre JUL, Log4j, Logback etc., o que facilita migrar sem reescrever o código.
5. Prática: comparando System.out.println e logging
Exemplo 1: System.out.println
public class PrintlnExample {
public static void main(String[] args) {
System.out.println("Aplicativo iniciado");
System.out.println("Ocorreu um erro: algo deu errado");
}
}
O que há de errado:
- Não há nível de mensagem (erro, informação, aviso — tudo fica igual).
- Não há horário, nome da classe, thread.
- Todas as mensagens vão para o mesmo lugar.
- Não é possível configurar a saída de forma flexível (por exemplo, registrar apenas erros).
Exemplo 2: logging com SLF4J + Logback
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LoggingVsPrintln {
private static final Logger logger = LoggerFactory.getLogger(LoggingVsPrintln.class);
public static void main(String[] args) {
logger.info("Aplicativo iniciado");
logger.error("Ocorreu um erro: algo deu errado");
}
}
Vantagens:
- Cada mensagem vem acompanhada de horário, nível, nome da classe e thread.
- É possível filtrar mensagens por nível.
- É possível escrever logs em arquivo, enviar pela rede, formatar, arquivar.
- O logging é thread-safe (importante para aplicativos multithread).
Demonstração da diferença
|
Logging (SLF4J/Logback) |
|---|---|
| Aplicativo iniciado | 12:34:56 [main] INFO LoggingVsPrintln - Aplicativo iniciado |
| Ocorreu um erro: algo deu errado | 12:34:56 [main] ERROR LoggingVsPrintln - Ocorreu um erro: algo deu errado |
6. Como adicionar logging ao seu projeto
Para o logger padrão (JUL)
Tudo já está na JDK; você pode usar imediatamente:
import java.util.logging.Logger;
public class MyApp {
private static final Logger logger = Logger.getLogger(MyApp.class.getName());
public static void main(String[] args) {
logger.info("Esta é uma mensagem de informação");
}
}
Para Log4j ou SLF4J
- Adicione as dependências (por exemplo, via Maven).
Para Log4j 2:
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.20.0</version> </dependency>Para SLF4J + Logback:
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.0.7</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.4.7</version> </dependency> - Crie o arquivo de configuração (por exemplo, logback.xml para o Logback ou log4j2.xml para o Log4j).
- Use o logger no seu código (veja os exemplos acima).
7. Miniaplicativo: adicionando logging
Suponha que temos um aplicativo simples — uma calculadora de linha de comando. Vamos adicionar logging a ele.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Scanner;
public class CalculatorApp {
private static final Logger logger = LoggerFactory.getLogger(CalculatorApp.class);
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
logger.info("Calculadora iniciada");
try {
System.out.print("Digite o primeiro número: ");
int a = Integer.parseInt(scanner.nextLine());
logger.debug("Primeiro número digitado: {}", a);
System.out.print("Digite o segundo número: ");
int b = Integer.parseInt(scanner.nextLine());
logger.debug("Segundo número digitado: {}", b);
int sum = a + b;
logger.info("Soma dos números: {}", sum);
System.out.println("Resultado: " + sum);
} catch (NumberFormatException ex) {
logger.error("Erro ao digitar o número", ex);
System.out.println("Erro: digite um número válido!");
} catch (Exception ex) {
logger.error("Erro desconhecido", ex);
System.out.println("Ocorreu um erro!");
}
logger.info("Calculadora finalizou a execução");
}
}
O que está acontecendo aqui:
- Todos os eventos-chave são registrados no log.
- Os erros são registrados no nível ERROR com o stack trace completo.
- Todas as informações ficam disponíveis para análise após a execução do programa.
8. Erros comuns ao trabalhar com logging
Erro nº 1: Usar apenas System.out.println para depuração e diagnóstico.
Isso é conveniente no início, mas não serve para aplicativos reais. Você não conseguirá controlar o nível das mensagens, não verá o horário e não poderá analisar os logs quando o programa estiver rodando no servidor.
Erro nº 2: Registrar informação demais no nível ERROR.
Se você marcar tudo como erro, deixará de distinguir o que é realmente importante do que é apenas informação para depuração.
Erro nº 3: Registrar dados sensíveis (senhas, tokens, números de cartão).
Os logs devem ser seguros! Não escreva neles o que outras pessoas não devem ver.
Erro nº 4: Falta de configuração do logging.
Se você não configurar níveis, formato e local de armazenamento dos logs, pode acabar “se afogando” em gigabytes de informação desnecessária ou nem enxergar um erro.
Erro nº 5: Não usar uma fachada de logging (SLF4J) em projetos grandes.
Se o seu projeto crescer e você precisar mudar de uma biblioteca para outra, sem uma fachada isso será doloroso. SLF4J permite trocar o “motor” de logging facilmente sem reescrever o código.
GO TO FULL VERSION