web-dev-qa-db-fra.com

Logger.getLogger (MyClass.class) est-il le meilleur moyen d'initialiser les enregistreurs log4j?

Ce tutoriel Mkyong suggère d'intialiser les enregistreurs de cette façon:

@Controller
public class WelcomeController {

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

   // etc

}

Maintenant, probablement toutes les autres classes que vous utilisez, qui ont un enregistreur initialiseront leurs enregistreurs de la même manière.

Ma question est - est-ce la meilleure façon de le faire? Cela semble ... répétitif.

13
dwjohnston

Votre commentaire dit que "verbeux" fait référence à la nécessité de répéter cette ligne de code dans chaque classe. Ma première réponse est que, dans l'ensemble, l'ajout de deux lignes de code (définition de variable plus déclaration d'importation) à chaque classe n'est pas si grave. D'autant plus que vous avez seulement besoin de les ajouter aux classes qui ont un comportement et doivent donc faire la journalisation. Cela dit, la ligne de code spécifique que vous utilisez est sujette à des erreurs de copier-coller (plus d'informations à ce sujet plus tard).

Mais, puisque vous voulez des alternatives, voici quelques-unes, avec des raisons pour lesquelles vous pourriez ou non vouloir les utiliser.

Utilisez un seul enregistreur pour toute l'application

Si vous ne vous souciez pas de la classe qui rapporte, ou si vous êtes prêt à mettre tout le contexte nécessaire dans le message, un simple enregistreur singleton fera le travail:

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

À mon avis, l'un des grands avantages d'un cadre de journalisation est que le contexte est fourni par des instances de journalisation distinctes - ne serait-ce que pour diriger les messages de journal vers différentes destinations. Je n'abandonnerais pas cela juste pour enregistrer une ligne de code (vous avez toujours besoin de l'importation).

De plus, cela augmente la verbosité au point d'utilisation, ce qui se traduira par beaucoup plus de frappes.

Créez vos enregistreurs au point d'utilisation

Je jette celui-ci juste parce qu'il élimine la variable. Je ne pense pas avoir besoin de commenter cela. Bien qu'il montre ma technique préférée pour obtenir une instance d'enregistreur.

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

Utilisez un post-processeur de bean pour injecter l'enregistreur

Votre exemple utilise Spring et Spring vous permet de vous connecter au code d'initialisation du bean. Vous pouvez créer un post-processeur qui inspecte le bean pour une variable membre logger et crée une instance Logger lorsqu'il en trouve une.

Bien qu'un tel post-processeur ne représente que quelques dizaines de lignes de code, c'est une autre partie mobile de votre application, et donc une autre source potentielle de bogues. Je préfère en avoir le moins possible.

Utilisez un mixin

Scala et Groovy fournissent traits, qui vous permettent d'encapsuler le comportement. Un modèle Scala modèle consiste à créer un trait Logging, puis à l'ajouter à la classe qui doit être journalisée:

class MyController with Logging

Malheureusement, cela signifie que vous devez changer de langue. Sauf si vous utilisez Java 8, auquel cas vous pouvez créer une interface Logging avec une "méthode par défaut":

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

Maintenant, dans votre code de classe, vous pouvez simplement utiliser

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

Bien que facile, cela présente quelques inconvénients. D'une part, il pollue l'interface de chaque classe qui l'utilise, car toutes les méthodes d'interface sont publiques. Peut-être pas si mal si vous l'utilisez uniquement pour les classes qui sont instanciées et injectées par Spring, surtout si vous suivez la séparation interface/implémentation.

Le plus gros problème est qu'il doit rechercher l'instance réelle de l'enregistreur à chaque appel. Ce qui est rapide, mais inutile.

Et vous avez toujours besoin d'une déclaration d'importation.

Déplacer l'enregistreur vers une superclasse

Je répète: je ne trouve pas verbeux les définitions répétées des enregistreurs, mais si vous le faites, je pense que c'est la meilleure approche pour les éliminer.

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

Vos classes de contrôleurs héritent maintenant de AbstractController et ont accès à la variable logger. N'oubliez pas que vous devez mettre l'annotation @Controller Sur la classe concrète.

Certaines personnes trouveront cela une perversion de l'héritage. J'ai essayé de les apaiser en nommant la classe AbstractController plutôt que AbstractProjectClass. Vous pouvez décider vous-même s'il existe ou non une relation is-a.

D'autres personnes s'opposeront à l'utilisation d'une variable d'instance plutôt que d'une variable statique. IMO les enregistreurs statiques sont sujets à des erreurs de copier-coller, car vous devez référencer explicitement le nom de classe; getClass() garantit que votre enregistreur est toujours correct.

16
kdgregory

Pour étendre la réponse fournie par @kdgregory, Groovy fournit @Slf4j (groovy.util.logging.Slf4j) hors de la boîte en tant qu'annotation qui effectue une transformation AST sur la classe pour la coller avec un enregistreur qui suppose le nom de variable log par défaut si elle n'est pas spécifiée.

0
Daniel Paul Anzaldo