2.1 Primeiro registrador - log4j

Como você já sabe, o histórico dos logs começou com System.err.println()a saída de um registro para o console. Ele ainda é usado ativamente para depuração, por exemplo, o Intellij IDEA o usa para exibir mensagens de erro no console. Mas esta opção não possui nenhuma configuração, então vamos em frente.

O primeiro e mais popular logger foi chamado Log4j. Foi uma solução boa e altamente personalizável. Devido a várias circunstâncias, essa decisão nunca chegou ao JDK, o que incomodou muito toda a comunidade.

Este logger não era apenas capaz de registrar, ele foi criado por programadores para programadores e permitiu que eles resolvessem problemas que surgiam constantemente em conexão com o registro.

Como você já sabe, os logs são gravados no final para que alguém os leia e tente entender o que aconteceu durante a operação do programa - o que e quando deu errado conforme o esperado.

Havia log4jtrês coisas para isso:

  • registro de subpacote;
  • conjunto de anexos (resultados);
  • configurações de recarga a quente.

Em primeiro lugar, as configurações log4jpodem ser escritas de forma a permitir o login em um pacote e desativá-lo em outro. Por exemplo, era possível habilitar o login no com.codegym.server, mas desativá-lo no com.codegym.server.payment. Isso possibilitou a remoção rápida de informações desnecessárias do log.

Em segundo lugar, log4jpermitia gravar os resultados do log em vários arquivos de log de uma só vez. E a saída para cada um pode ser configurada individualmente. Por exemplo, em um arquivo era possível gravar apenas informações sobre erros graves, em outro - logs de um módulo específico e em um terceiro - logs por um determinado período.

Cada arquivo de log foi ajustado para um tipo específico de problema esperado. Isso simplifica muito a vida dos programadores que não gostam de examinar manualmente os arquivos de log de gigabytes.

E finalmente, em terceiro lugar, log4jpermitiu alterar as configurações do log diretamente enquanto o programa estava em execução, sem reiniciá-lo. Isso foi muito útil quando era necessário corrigir o trabalho dos logs para encontrar informações adicionais sobre um erro específico.

Importante! Existem duas versões do log log4j: 1.2.xe 2.xx , que são incompatíveis entre si .

Você pode conectar o logger ao projeto usando o código:

<dependencies>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.2</version>
  </dependency>

  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.2</version>
  </dependency>
</dependencies>

2.2 Primeiro registrador oficial - JUL: java.util.logging

Depois que o zoológico de madeireiros apareceu na comunidade Java, os desenvolvedores JDKdecidiram fazer um logger padrão que todos usariam. Foi assim que o logger apareceu JUL: package java.util.logging.

Porém, durante seu desenvolvimento, os criadores do logger tomaram como base não log4j, mas uma variante do logger da IBM, que influenciou seu desenvolvimento. A boa notícia é que o logger JULestá incluso JDK, a má notícia é que poucas pessoas o utilizam.

julho

Os desenvolvedores não apenas JULcriaram “outro padrão universal” , mas também criaram seus próprios níveis de registro para ele, que diferiam daqueles aceitos pelos madeireiros populares na época.

E isso foi um grande problema. Afinal, os produtos Javageralmente são coletados de um grande número de bibliotecas, e cada uma dessas bibliotecas tinha seu próprio registrador. Então foi necessário configurar todos os loggers que estão no aplicativo.

Embora o logger em si seja muito bom. Criar um logger é mais ou menos o mesmo. Para fazer isso, você precisa importar:


java.util.logging.Logger log = java.util.logging.Logger.getLogger(LoggingJul.class.getName());

O nome da classe é passado especialmente para saber de onde vem o registro.

Somente com o lançamento, os desenvolvedores resolveram problemas importantes, após os quais é JULrealmente conveniente de usar. Antes disso, era uma espécie de madeireiro de segunda categoria.

Este logger também oferece suporte a expressões lambda e avaliação preguiçosa. Começando com Java 8, você pode passar Supplier<String>. Isso ajuda a ler e criar uma string apenas no momento em que ela é realmente necessária, e não sempre, como antes.

Métodos com um argumento Supplier<String> msgSupplierse parecem com isso:

public void info(Supplier msgSupplier) {
   log(Level.INFO, msgSupplier);
}

2.3 Primeiro logger wrapper - JCL: registro em log comum de jacarta

Por muito tempo não havia um padrão único entre os madeireiros, JULdeveria ter se tornado um, mas foi pior log4j, então nunca apareceu um padrão único. Mas apareceu todo um zoológico de madeireiros, cada um dos quais queria se tornar o mesmo.

JCL

No entanto, os desenvolvedores Java comuns não gostaram que quase todas as bibliotecas tivessem seu próprio logger e precisassem ser configuradas de alguma forma especial. Portanto, a comunidade decidiu criar um wrapper especial sobre outros madeireiros - é assimJCL: jakarta commons logging

E, novamente, o projeto, que foi criado para ser líder, não se tornou um. Você não pode criar um vencedor, você só pode se tornar um vencedor. A funcionalidade JCLera muito ruim e ninguém queria usá-la. O madeireiro, projetado para substituir todos os madeireiros, teve o mesmo destino, pois JULnão foi usado.

Embora tenha sido adicionado a muitas bibliotecas lançadas pela comunidade Apache, o zoológico de madeireiros só cresceu.

2.4 Primeiro último registrador - Logback

Mas isso não é tudo. O desenvolvedor log4jdecidiu que ele era o mais inteligente (bem, afinal, a maioria das pessoas usava seu logger) e decidiu escrever um novo logger aprimorado que combinaria as vantagens log4jde outros loggers.

O novo registrador foi chamado Logback. Era esse registrador que deveria se tornar o futuro registrador único que todos usariam. Foi baseado na mesma ideia que em log4j.

Você pode conectar este logger ao projeto usando o código:

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.6</version>
</dependency>

As diferenças estavam em Logback:

  • performance melhorada;
  • adicionado suporte nativo slf4j;
  • opção de filtragem expandida.

Outra vantagem desse logger era que ele tinha configurações padrão muito boas. E você tinha que configurar o logger apenas se quisesse mudar algo neles. Além disso, o arquivo de configurações foi melhor adaptado ao software corporativo - todas as suas configurações foram definidas como xml/.

Por padrão, Logbackele não requer nenhuma configuração e registra todos os logs do nível DEBUGe acima. Se você precisar de um comportamento diferente, pode ser configurado via xmlconfiguração:

<configuration>
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>app.log</file>
        <encoder>
            <pattern>%d{HH:mm:ss,SSS} %-5p [%c] - %m%n</pattern>
        </encoder>
    </appender>
    <logger name="org.hibernate.SQL" level="DEBUG" />
    <logger name="org.hibernate.type.descriptor.sql" level="TRACE" />
    <root level="info">
        <appender-ref ref="FILE" />
    </root>
</configuration>

2.5 Registrador universal mais recente - SLF4J: Fachada de registro simples para Java

Quanto tempo pode demorar para encontrar o meio-termo...

Em 2006, um dos criadores log4jdeixou o projeto e decidiu tentar novamente criar um registrador universal. Mas desta vez não era um novo logger, mas um novo padrão universal (wrapper) que permitia que diferentes loggers interagissem entre si.

Este logger foi chamado slf4j — Simple Logging Facade for Java, era um wrapper em torno de log4j, JUL, common-loggins and logback. Este madeireiro resolveu um problema real - gerenciar um zoológico de madeireiros, então todos começaram a usá-lo imediatamente.

Resolvemos heroicamente os problemas que criamos para nós mesmos. Como você pode ver, o progresso chegou ao ponto em que criamos um wrapper sobre o wrapper ...

O envoltório em si consiste em duas partes:

  • API, que é usado em aplicativos;
  • Implementações que são adicionadas como dependências separadas para cada criador de logs.

Você pode conectar o logger ao projeto usando o código:

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

Basta conectar a implementação correta e pronto: todo o projeto funcionará com ela.

2.6 Otimização em slf4j

Slf4jsuporta todos os novos recursos, como formatação de string para registro . Antes disso, havia um problema tão grande. Digamos que você queira imprimir uma mensagem no log:

log.debug("User " + user + " connected from " + request.getRemoteAddr());

Há um problema com este código. Suponha que seu aplicativo funcione productione não grave nada no log DEBUG-messages, no entanto, o método log.debug()ainda será chamado e, quando for chamado, os seguintes métodos também serão chamados:

  • user.toString();
  • request.getRemoteAddr();

Chamar esses métodos torna o aplicativo mais lento. A chamada deles é necessária apenas durante a depuração, mas eles são chamados de qualquer maneira.

Do ponto de vista da lógica, esse problema teve que ser resolvido na própria biblioteca de logging. E na primeira versão do log4j surgiu a solução:

if (log.isDebugEnabled()) {
    log.debug("User " + user + " connected from " + request.getRemoteAddr());
}

Em vez de uma linha para o log, agora era preciso escrever três. O que piorou drasticamente a legibilidade do código e diminuiu a popularidade do log4j.

O registrador slf4jconseguiu melhorar um pouco a situação oferecendo registro inteligente. Ficou assim:

log.debug("User {} connected from {}", user, request.getRemoteAddr());

where {}denotam a inserção de argumentos que são passados ​​no método. Ou seja, o primeiro {}corresponde ao usuário, o segundo {}ao request.getRemoteAddr().

Esses parâmetros serão concatenados em uma única mensagem somente se o nível de registro permitir o registro. Não é perfeito, mas melhor do que todas as outras opções.

Depois disso, SLF4Jcomeçou a crescer rapidamente em popularidade, no momento esta é a melhor solução.

Portanto, consideraremos o log usando o exemplo de um bundle slf4j-log4j12.