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


13

Ce didacticiel Mkyong propose 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.


2
Que trouvez-vous détaillé à ce sujet (en mettant de côté la syntaxe Java)?. Vous devez créer une variable pour contenir l'enregistreur et vous devez indiquer getLogger()le nom de l'enregistreur à obtenir.
kdgregory

2
@kdgregory le fait que je fais la même chose dans chaque classe.
dwjohnston

1
Jetez un oeil à cette question sur Stack Overflow
toniedzwiedz

3
Trop vieux pour migrer, mais cette question est hors sujet ici et plus adaptée à StackOverflow.
Andres F.

1
@AndresF. Je pense que je l'ai mis ici parce qu'il s'agit plus d'une question de style de code / de modèles de conception que d'un problème technique.
dwjohnston

Réponses:


16

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 d'enregistreur 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 loggervariable membre et crée une Loggerinstance 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 des traits qui vous permettent d'encapsuler le comportement. Un modèle Scala typique consiste à créer un Loggingtrait, 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 Logginginterface 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 ne l'utilisez que pour des classes 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 d'enregistreurs répétées, 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());
}

Maintenant, vos classes de contrôleurs héritent de AbstractControlleret ont accès à la loggervariable. N'oubliez pas que vous devez mettre l' @Controllerannotation 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 AbstractControllerplutôt que AbstractProjectClass. Vous pouvez décider vous-même s'il existe ou non une relation est-une .

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


Je pense que vous devriez faire attention à getClass () dans la classe d'héritage, MethodHandles.lookup (). LookupClass () est meilleur après jdk 7
yuxh

@luxh - avez-vous une explication à cela?
kdgregory


@yuxh - la seule mention de MethodHandles dans cette question (qui n'était pas dans la réponse que vous avez liée), est une assertion similaire non prise en charge avec un commentaire demandant des éclaircissements. Avez-vous un soutien faisant autorité pour l'affirmation qui MethodHandles.lookup().lookupClass()est meilleure que Object.getClass()?
kdgregory

MethodHandles.lookup().lookupClass()peut être utilisé pour les variables statiques, n'est pas sujet aux erreurs de copier-coller et est rapide: stackoverflow.com/a/47112323/898747 Cela signifie un inport supplémentaire, mais j'aime beaucoup mes enregistreurs statiques, donc cela vaut au moins la peine mention :)
FableBlaze

0

Pour étendre la réponse fournie par @kdgregory, Groovy fournit @Slf4j( groovy.util.logging.Slf4j) hors de la boîte comme une annotation qui effectue une transformation AST sur la classe pour la clouer avec un enregistreur qui assume le nom de variable logpar défaut s'il n'est pas spécifié.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.