O Logger.getLogger (MyClass.class) é a melhor maneira de inicializar os log4j loggers?

13

Este tutorial da Mkyong sugere a inicialização de loggers desta maneira:

@Controller
public class WelcomeController {

    private static final Logger logger = Logger.getLogger(WelcomeController.class);

   // etc

}

Agora, presumivelmente, todas as outras classes que você usa, que possuem um logger, inicializarão seus loggers da mesma maneira.

Minha pergunta é - essa é a melhor maneira de fazer isso? Parece ... repetitivo.

Dwjohnston
fonte
2
O que você acha detalhado sobre isso (deixando de lado a sintaxe do Java) ?. Você precisa criar uma variável para conter o logger e informar getLogger()o nome do logger para obter.
kdgregory
2
@kdgregory o fato de estar fazendo a mesma coisa em todas as aulas.
dwjohnston
1
Dê uma olhada nesta pergunta no Stack Overflow
toniedzwiedz
3
Demasiado antigo para migrar, mas esta pergunta está fora de tópico aqui e é mais adequada para StackOverflow.
Andres F.
1
@AndresF. Acho que coloquei aqui porque é mais uma questão sobre estilo de código / padrões de design do que uma questão técnica.
dwjohnston

Respostas:

16

Seu comentário diz que "detalhado" refere-se à necessidade de repetir essa linha de código em todas as classes. Minha primeira resposta é que, em geral, adicionar duas linhas de código (definição de variável mais declaração de importação) a todas as classes não é tão importante. Especialmente porque você só precisa adicioná-los às classes que têm comportamento e, portanto, precisam fazer log. Dito isto, a linha de código específica que você está usando é propensa a erros de copiar e colar (mais sobre isso mais tarde).

Mas, como você deseja alternativas, eis algumas, com motivos pelos quais você pode ou não usá-las.

Use um único logger para todo o aplicativo

Se você não se importa com o que a classe está relatando ou está disposto a colocar todo o contexto necessário na mensagem, um simples registrador singleton fará o trabalho:

LoggerSingleton.getInstance().debug("MyController is running")

Na minha opinião, um dos grandes benefícios de uma estrutura de log é ter o contexto fornecido por instâncias separadas do criador de logs - apenas para direcionar as mensagens de log para diferentes destinos. Eu não desistiria disso apenas para salvar uma linha de código (você ainda precisa da importação).

Além disso, isso aumenta a verbosidade no ponto de uso, o que acaba resultando em muito mais pressionamentos de tecla.

Crie seus loggers no ponto de uso

Estou jogando este fora apenas porque elimina a variável. Eu não acho que preciso comentar sobre isso. Embora ele mostre minha técnica preferida para obter uma instância do logger.

Logger.getLogger(getClass()).debug("blah blah blah");

Use um pós-processador de bean para injetar o criador de logs

Seu exemplo usa Spring, e o Spring permite conectar o código de inicialização do bean. Você pode criar um pós-processador que inspeciona o bean para uma loggervariável de membro e cria uma Loggerinstância quando encontra uma.

Embora esse pós-processador seja apenas algumas dezenas de linhas de código, é outra parte importante do seu aplicativo e, portanto, outra fonte potencial de erros. Eu prefiro ter o menor número possível deles.

Use um mixin

Scala e Groovy fornecem características , que permitem encapsular o comportamento. Um padrão Scala típico é criar uma Loggingcaracterística e adicioná-la à classe que precisa ser registrada:

class MyController with Logging

Infelizmente, isso significa que você precisa mudar de idioma. A menos que você esteja usando o Java 8, nesse caso, você pode criar uma Logginginterface com um "método padrão":

public interface Logging {
    default Logger getLogger() {
        return Logger.getLogger(getClass());
    } 
}

Agora, dentro do seu código de classe, você pode simplesmente usar

getLogger().debug("blah blah blah");

Embora fácil, isso tem algumas desvantagens. Por um lado, polui a interface de todas as classes que a usam, porque todos os métodos de interface são públicos. Talvez não seja tão ruim se você o usar apenas para classes instanciadas e injetadas pelo Spring, especialmente se você seguir a separação interface / implementação.

O maior problema é que ele precisa procurar a instância real do criador de logs em todas as chamadas. O que é rápido, mas desnecessário.

E você ainda precisa de uma declaração de importação.

Mover o registrador para uma superclasse

Vou repetir: não acho as definições repetidas do criador de logs detalhadas, mas se você acha que essa é a melhor abordagem para eliminá-las.

public abstract class AbstractController {
    protected Logger logger = Logger.getLogger(getClass());
}

Agora suas classes de controlador herdam AbstractControllere elas têm acesso à loggervariável. Lembre-se de que você deve colocar a @Controlleranotação na classe concreta.

Algumas pessoas acharão isso uma perversão da herança. Tentei acalmá-los nomeando a classe em AbstractControllervez de AbstractProjectClass. Você pode decidir por si mesmo se existe ou não um relacionamento.

Outras pessoas se oporão ao uso de uma variável de instância em vez de uma variável estática. Os registradores estáticos da IMO tendem a copiar e colar erros, porque você precisa fazer referência explícita ao nome da classe; getClass()garante que seu criador de logs esteja sempre correto.

kdgregory
fonte
Eu acho que você deve ter cuidado com getClass () na classe herança, MethodHandles.lookup () lookupClass () é melhor após o JDK 7.
yuxh
@luxh - você tem uma explicação para isso?
Kdgregory 16/07/19
Verifique aqui: stackoverflow.com/a/6653577/4652536
yuxh 01/08/19
@yuxh - a única menção de MethodHandles nessa pergunta (que não estava na resposta que você vinculou) é uma afirmação sem suporte semelhante com um comentário pedindo esclarecimentos. Você tem autoridade suporte para a afirmação de que MethodHandles.lookup().lookupClass()é melhor do que Object.getClass()?
Kdgregory 01/08/19
MethodHandles.lookup().lookupClass()pode ser usado para variáveis ​​estáticas, não é propenso a erros de copiar e colar e é rápido: stackoverflow.com/a/47112323/898747 Isso significa uma entrada extra, mas eu gosto que meus registradores sejam estáticos, pelo menos vale a pena Menção :)
FableBlaze 19/02
0

Para estender a resposta fornecida por @kdgregory, o Groovy fornece @Slf4j( groovy.util.logging.Slf4j) imediatamente como uma anotação que executa uma transformação AST na classe para aderi-la a um registrador que assume o nome da variável logpor padrão, se não for especificado.

Daniel Paul Anzaldo
fonte