Pour la première fois de ma vie, je me retrouve dans une position où j'écris une API Java qui sera open source. J'espère être inclus dans de nombreux autres projets.
Pour la journalisation, j'ai (et en effet les personnes avec qui je travaille) j'ai toujours utilisé JUL (java.util.logging) et je n'ai jamais eu de problème avec. Cependant, maintenant, je dois comprendre plus en détail ce que je dois faire pour le développement de mon API. J'ai fait des recherches à ce sujet et avec les informations que j'ai, je suis encore plus confus. D'où ce post.
Depuis que je viens de JUL, je suis partisan de cela. Ma connaissance du reste n'est pas si grande.
D'après les recherches que j'ai faites, j'ai trouvé ces raisons pour lesquelles les gens n'aiment pas JUL:
"J'ai commencé à développer en Java bien avant la sortie de Sun de JUL et il était plus facile pour moi de continuer avec logging-framework-X plutôt que d'apprendre quelque chose de nouveau" . Hmm. Je ne plaisante pas, c'est en fait ce que les gens disent. Avec cet argument, nous pourrions tous faire du COBOL. (mais je peux certainement comprendre que c'est un mec paresseux moi-même)
"Je n'aime pas les noms des niveaux de journalisation en JUL" . Ok, sérieusement, ce n'est tout simplement pas une raison suffisante pour introduire une nouvelle dépendance.
"Je n'aime pas le format standard de la sortie de JUL" . Hmm. C'est juste une configuration. Vous n'avez même rien à faire au niveau du code. (c'est vrai, dans le passé, vous avez peut-être dû créer votre propre classe Formatter pour bien faire les choses).
"J'utilise d'autres bibliothèques qui utilisent également logging-framework-X, donc j'ai pensé qu'il était plus facile de simplement utiliser celle-là" . C'est un argument circulaire, non? Pourquoi «tout le monde» utilise logging-framework-X et non JUL?
"Tout le monde utilise logging-framework-X" . Pour moi, ce n'est qu'un cas particulier de ce qui précède. La majorité n'a pas toujours raison.
La vraie grande question est donc pourquoi pas JUL? . Qu'est-ce que j'ai manqué? La raison d'être des façades de journalisation (SLF4J, JCL) est que plusieurs implémentations de journalisation ont existé historiquement et que la raison de cela remonte vraiment à l'époque d'avant JUL telle que je la vois. Si JUL était parfait, les façades d'abattage n'existeraient pas, ou quoi? Pour rendre les choses plus confuses, JUL est dans une certaine mesure une façade elle-même, permettant aux gestionnaires, aux formateurs et même au LogManager d'être échangés.
Plutôt que d'embrasser plusieurs façons de faire la même chose (enregistrement), ne devrions-nous pas nous demander pourquoi elles étaient nécessaires en premier lieu? (et voir si ces raisons existent toujours)
Ok, mes recherches jusqu'à présent ont conduit à quelques choses que je peux voir peuvent être de vrais problèmes avec JUL:
Performance . Certains disent que les performances du SLF4J sont supérieures aux autres. Cela me semble être un cas d'optimisation prématurée. Si vous devez enregistrer des centaines de mégaoctets par seconde, je ne suis pas sûr que vous soyez de toute façon sur la bonne voie. JUL a également évolué et les tests que vous avez faits sur Java 1.4 peuvent ne plus être vrais. Vous pouvez en savoir plus ici et ce correctif a été intégré à Java 7. Beaucoup parlent également de la surcharge de la concaténation de chaînes dans les méthodes de journalisation. Cependant, la journalisation basée sur un modèle évite ce coût et existe également en juillet. Personnellement, je n'écris jamais vraiment une journalisation basée sur un modèle. Trop paresseux pour ça. Par exemple, si je fais cela avec JUL:
log.finest("Lookup request from username=" + username + ", valueX=" + valueX + ", valueY=" + valueY));
mon IDE m'avertira et me demandera la permission de le changer en:
log.log(Level.FINEST, "Lookup request from username={0}, valueX={1}, valueY={2}", new Object[]{username, valueX, valueY});
.. que j'accepterai bien sûr. Permission accordée ! Merci de votre aide.
Donc je n'écris pas de telles déclarations moi-même, c'est fait par l'IDE.
En conclusion sur la question de la performance, je n'ai rien trouvé qui puisse suggérer que la performance de JUL n'est pas correcte par rapport à la concurrence.
Configuration à partir de classpath . JUL prêt à l'emploi ne peut pas charger un fichier de configuration à partir du chemin de classe. Il suffit de quelques lignes de code pour le faire. Je peux voir pourquoi cela peut être ennuyeux mais la solution est courte et simple.
Disponibilité des gestionnaires de sortie . JUL est livré avec 5 gestionnaires de sortie prêts à l'emploi: console, flux de fichiers, socket et mémoire. Ceux-ci peuvent être étendus ou de nouveaux peuvent être écrits. Cela peut par exemple être écrit dans UNIX / Linux Syslog et le journal des événements Windows. Personnellement, je n'ai jamais eu cette exigence et je ne l'ai jamais vue utilisée, mais je peux certainement comprendre pourquoi elle peut être une fonctionnalité utile. Logback est fourni avec un appender pour Syslog par exemple. Je dirais néanmoins que
- 99,5% des besoins en destinations de sortie sont couverts par ce qui se trouve dans JUL prêt à l'emploi.
- Les besoins spéciaux pourraient être pris en charge par des gestionnaires personnalisés en plus de JUL plutôt qu'en plus d'autre chose. Il n'y a rien pour moi qui suggère qu'il faut plus de temps pour écrire un gestionnaire de sortie Syslog pour JUL que pour un autre framework de journalisation.
Je suis vraiment préoccupé par le fait que j'ai oublié quelque chose. L'utilisation de façades de journalisation et d'implémentations de journalisation autres que JUL est si répandue que je dois en conclure que c'est moi qui ne comprends tout simplement pas. Ce ne serait pas la première fois, je le crains. :-)
Alors, que dois-je faire avec mon API? Je veux que ça réussisse. Je peux bien sûr simplement "suivre le courant" et implémenter SLF4J (qui semble le plus populaire de nos jours) mais pour moi-même, j'ai encore besoin de comprendre exactement ce qui ne va pas avec le JUL d'aujourd'hui qui mérite tout le fuzz? Vais-je me saboter en choisissant JUL pour ma bibliothèque?
Test des performances
(section ajoutée par nolan600 le 07-JUL-2012)
Il y a une référence ci-dessous de Ceki sur le paramétrage de SLF4J étant 10 fois ou plus rapide que JUL. J'ai donc commencé à faire des tests simples. À première vue, l'affirmation est certainement correcte. Voici les résultats préliminaires (mais lisez la suite!):
- Temps d'exécution SLF4J, backend Logback: 1515
- Temps d'exécution SLF4J, backend JUL: 12938
- Temps d'exécution JUL: 16911
Les nombres ci-dessus sont msec donc moins c'est mieux. Donc, une différence de performances de 10 fois est d'abord assez proche. Ma première réaction: c'est beaucoup!
Voici l'essentiel du test. Comme on peut le voir, un entier et une chaîne sont construits dans une boucle qui est ensuite utilisée dans l'instruction log:
for (int i = 0; i < noOfExecutions; i++) {
for (char x=32; x<88; x++) {
String someString = Character.toString(x);
// here we log
}
}
(Je voulais que l'instruction log ait à la fois un type de données primitif (dans ce cas, un int) et un type de données plus complexe (dans ce cas, une chaîne). Je ne suis pas sûr que cela soit important mais vous l'avez.)
L'instruction de journal pour SLF4J:
logger.info("Logging {} and {} ", i, someString);
L'instruction de journal pour JUL:
logger.log(Level.INFO, "Logging {0} and {1}", new Object[]{i, someString});
La JVM a été «réchauffée» avec le même test exécuté une fois avant la mesure proprement dite. Java 1.7.03 a été utilisé sur Windows 7. Les dernières versions de SLF4J (v1.6.6) et Logback (v1.0.6) ont été utilisées. Stdout et stderr ont été redirigés vers un périphérique nul.
Cependant, attention maintenant, il s'avère que JUL passe la plupart de son temps getSourceClassName()
car JUL affiche par défaut le nom de la classe source dans la sortie, contrairement à Logback. Nous comparons donc des pommes et des oranges. Je dois refaire le test et configurer les implémentations de journalisation de manière similaire afin qu'elles produisent réellement le même contenu. Je soupçonne cependant que SLF4J + Logback sortira toujours en tête mais loin des chiffres initiaux indiqués ci-dessus. Restez à l'écoute.
Btw: Le test était la première fois que je travaillais avec SLF4J ou Logback. Une expérience agréable. JUL est certainement beaucoup moins accueillant lorsque vous débutez.
Test des performances (partie 2)
(section ajoutée par nolan600 le 08-JUL-2012)
En fin de compte, peu importe pour les performances la façon dont vous configurez votre modèle dans JUL, c'est-à-dire s'il inclut ou non le nom de la source. J'ai essayé avec un motif très simple:
java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"
et cela n'a pas du tout changé les horaires ci-dessus. Mon profileur a révélé que l'enregistreur passait encore beaucoup de temps à appeler getSourceClassName()
même si cela ne faisait pas partie de mon schéma. Le motif n'a pas d'importance.
Je conclus donc sur la question des performances qu'au moins pour l'instruction de journal basée sur un modèle testé, il semble y avoir environ un facteur de 10 dans la différence de performances réelles entre JUL (lent) et SLF4J + Logback (rapide). Tout comme Ceki l'a dit.
Je peux également voir une autre chose, à savoir que l' getLogger()
appel de SLF4J est beaucoup plus cher que idem pour JUL. (95 ms vs 0,3 ms si mon profileur est précis). C'est logique. SLF4J doit faire un certain temps sur la liaison de l'implémentation de journalisation sous-jacente. Cela ne me fait pas peur. Ces appels devraient être quelque peu rares dans la durée de vie d'une application. La solidité doit être dans les appels de journal réels.
Conclusion finale
(section ajoutée par nolan600 le 08-JUL-2012)
Merci pour toutes vos réponses. Contrairement à ce que je pensais au départ, j'ai fini par décider d'utiliser SLF4J pour mon API. Ceci est basé sur un certain nombre de choses et sur votre contribution:
Il offre la flexibilité de choisir l'implémentation des journaux au moment du déploiement.
Problèmes avec le manque de flexibilité de la configuration de JUL lorsqu'elle est exécutée à l'intérieur d'un serveur d'applications.
SLF4J est certainement beaucoup plus rapide comme détaillé ci-dessus en particulier si vous le couplez avec Logback. Même si ce n'était qu'un test approximatif, j'ai des raisons de croire que beaucoup d'efforts ont été consacrés à l'optimisation sur SLF4J + Logback que sur JUL.
Documentation. La documentation du SLF4J est tout simplement beaucoup plus complète et précise.
Flexibilité du motif. Comme je l'ai fait les tests, j'ai décidé d'avoir JUL imiter le modèle par défaut de Logback. Ce modèle inclut le nom du thread. Il s'avère que JUL ne peut pas faire cela hors de la boîte. Ok, je ne l'ai pas manqué jusqu'à présent, mais je ne pense pas que ce soit une chose qui devrait manquer dans un cadre de log. Période!
La plupart (ou beaucoup) de projets Java utilisent aujourd'hui Maven, donc l'ajout d'une dépendance n'est pas si important, surtout si cette dépendance est plutôt stable, c'est-à-dire qu'elle ne change pas constamment son API. Cela semble être vrai pour SLF4J. Le pot SLF4J et ses amis sont également de petite taille.
Donc, la chose étrange qui s'est produite, c'est que j'ai été assez contrarié par JUL après avoir un peu travaillé avec SLF4J. Je regrette toujours que ce soit le cas avec JUL. JUL est loin d'être parfait mais fait le travail. Mais pas assez bien. La même chose peut être dite à Properties
titre d'exemple, mais nous ne pensons pas à l'abstraire pour que les gens puissent brancher leur propre bibliothèque de configuration et ce que vous avez. Je pense que la raison en est que cela Properties
vient juste au-dessus de la barre alors que le contraire est vrai pour JUL d'aujourd'hui ... et dans le passé, il était à zéro parce qu'il n'existait pas.
java.lang.System.Logger
, qui est une interface , qui peut être redirigée vers le cadre de journalisation réel que vous souhaitez, tant que ce cadre est rattrapé et fournit une implémentation de cette interface. Combiné à la modularisation, vous pouvez même déployer une application avec un JRE intégré ne contenant pas java.util.logging
, si vous préférez un framework différent.