Pourquoi ne pas utiliser java.util.l'exploitation forestière?


Pour la première fois de ma vie, je me trouve dans une position où j'écris une API Java qui sera open source. Espérons être inclus dans de nombreux autres projets.

Pour la journalisation, je (et en effet les personnes avec lesquelles je travaille) ai toujours utilisé JUL (java.util.logging) et n'a jamais eu de problèmes avec cela. Cependant, maintenant, je dois comprendre plus en détail ce que je dois faire pour mon développement d'API. J'ai fait des recherches à ce sujet et avec les informations que j'ai, je deviens plus confus. Conséquent ce post.

Puisque je viens de JUL, je suis partial à ce sujet. Ma connaissance du reste n'est pas si grande.

De la recherche que j'ai faite, je suis venu avec ces raisons pour lesquelles les gens n'aiment pas JUL:

  1. "J'ai commencé à développer en Java bien avant que Sun ne publie JUL et c'était juste plus facile pour moi de continuer avec logging-framework-X plutôt que d'apprendre quelque chose de nouveau". Hum. Je ne plaisante pas, c'est en fait ce que les gens disent. Avec cet argument nous pourrions tous faire COBOL. (cependant, je peux certainement comprendre que ce soit moi-même un mec paresseux)

  2. "je n'aime pas les noms des niveaux de journalisation dans JUL". Ok, sérieusement, ce n'est tout simplement pas une raison suffisante pour introduire une nouvelle dépendance.

  3. "je n'aime pas le format standard de la sortie de JUL". Hum. Ceci est juste la configuration. Vous n'avez même pas à faire quoi que ce soit en termes de code. (c'est vrai, dans les temps anciens, vous avez peut-être dû créer le vôtre Classe de formateur pour bien faire les choses).

  4. "je utiliser d'autres bibliothèques qui utilisent également la journalisation-cadre-X, donc j'ai pensé qu'il plus facile à utiliser que l'on". C'est une reprise cyclique de l'argument, n'est-ce pas ? Pourquoi "tout le monde" utilise-t-il logging-framework-X et non JUL?

  5. "tout le monde est à l'aide de journalisation-cadre-X". Ceci pour moi est juste un cas particulier de ce qui précède. La majorité n'a pas toujours raison.

Donc la vraie grande question est pourquoi pas JUL?. Qu'est-ce que j'ai raté ? La raison d'être des façades de journalisation (SLF4J, JCL) est que plusieurs implémentations de journalisation ont existé historiquement et la raison de cela remonte vraiment à l'époque avant JUL telle que je la vois. Si JUL était parfait, alors les façades d'exploitation forestière n'existeraient pas, ou quoi? Plutôt que de les embrasser, ne devrions-nous pas nous demander pourquoi ils étaient nécessaires en premier lieu? (et voir si ces raisons existent toujours)

Ok, mes recherches jusqu'à présent ont conduit à quelques choses ce que je peux voir peut être problèmes réels avec JUL:

  1. Les Performances. Certains disent que les performances dans 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 sur le bon chemin de toute façon. JUL a également évolué et les tests que vous avez effectués sur Java 1.4 peuvent ne plus être vrais. Vous pouvez lire à ce sujet ici et ce correctif l'a transformé en Java 7. Beaucoup parlent aussi à propos de la surcharge de la concaténation de chaînes dans les méthodes de journalisation. Cependant, la journalisation basée sur le modèle évite ce coût et il existe également en juillet. Personnellement, je n'écris jamais vraiment de journalisation basée sur un modèle. Trop paresseux pour cela. Par exemple, si je le fais avec JUL:

    log.finest("Lookup request from username=" + username 
       + ", valueX=" + valueX
       + ", valueY=" + valueY));
    

    MonE me préviendra 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});
    

    .. qui je vais bien sûr accepter. L'autorisation accordée ! Je vous remercie pour votre aide.

    Donc je n'écris pas moi-même de telles déclarations, ce qui est fait par l'IDE.

    En conclusion sur la question de la performance, je n'ai rien trouvé qui suggère que la performance de JUL n'est pas correcte par rapport à la concurrence.

  2. Configuration à partir de classpath . Prêt à l'emploi, JUL ne peut pas charger un fichier de configuration à partir du chemin de classe. Il est un quelques lignes de code pour ce faire. Je peux voir pourquoi cela peut être ennuyeux mais la solution est courte et simple.

  3. 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 un Syslog UNIX/Linux et dans le journal des événements Windows. J'ai personnellement jamais eu cette exigence n'ai vu utilisé, mais je comprends pourquoi il peut être très utile. Logback est livré avec un appender pour Syslog par exemple. Je dirais que

    1. 99,5% des besoins les destinations de sortie sont couvertes par ce qui est en JUILLET prêt à l'emploi.
    2. Les besoins spéciaux pourraient être pris en charge par des gestionnaires personnalisés au-dessus de JUL plutôt que par-dessus 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 quelque chose que j'ai négligé. L'utilisation de façades de journalisation et d'implémentations de journalisation autres que JUL est si répandu que je dois arriver à la conclusion que c'est moi qui ne comprends tout simplement pas. Ce ne serait pas la première fois, j'en ai bien peur. :-)

Alors, que dois-je faire avec mon API? Je veux qu'il devienne un succès. Je peux bien sûr juste "aller avec le flux" et implémenter SLF4J (qui semble le plus populaire de nos jours) mais pour mon propre bien, j'ai encore besoin de comprendre exactement ce qui ne va pas avec le JUL d'aujourd'hui qui justifie tous les fuzz? Vais-je me saboter en choisissant JUL pour ma bibliothèque ?

Performances de test

(section ajoutée par nolan600 le 07-JUL-2012)

Il y a une référence ci-dessous de Ceki sur la paramétrisation de SLF4J étant 10 fois ou plus rapide que celle de JUL. J'ai donc commencé à faire quelques 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 JUIL: 12938
  • temps d'Exécution JUIL: 16911

Les chiffres ci-dessus sont msecs donc moins c'est mieux. Donc, 10 fois la différence de performance est d'abord assez proche. Ma première réaction: C'est beaucoup !

Voici le cœur du test. Comme on peut le voir, un entier et une chaîne sont interprétés 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). Pas bien sûr, cela compte, mais vous l'avez.)

L'instruction log pour SLF4J:

logger.info("Logging {} and {} ", i, someString);

L'instruction log pour JUIL:

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 que la mesure réelle ne soit effectuée. Java 1.7.03 a été utilisé sur Windows 7. Les dernières versions de SLF4J (v1.6.6) et de Logback (v1.0.6) ont été utilisées. Stdout et stderr ont été redirigés vers le périphérique null.

Cependant, attention maintenant, il s'avère que JUL passe la plupart de son temps dans getSourceClassName() parce que JUL par défaut, imprime le nom de la classe source dans la sortie, alors que Logback ne le fait pas. Nous comparons donc des pommes et des oranges. Je dois refaire le test et configurer les implémentations de journalisation d'une manière similaire afin qu'elles produisent réellement les mêmes choses. Je soupçonne cependant que SLF4J + Logback sortira toujours en tête mais loin des chiffres initiaux donné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 commencez.

Performances de test (partie 2)

(section ajoutée par nolan600 le 08-JUL-2012)

Il s'avère que la façon dont vous configurez votre modèle en juillet n'a pas vraiment d'importance pour les performances, c'est-à-dire s'il inclut ou non le nom 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 dans appels à getSourceClassName() même si cela ne faisait pas partie de mon modèle. Le modèle 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 performance réelle entre JUL (lent) et SLF4J+Logback (rapide). Comme Ceki l'a dit.

Je peux aussi voir une autre chose à savoir que l'appel de SLF4J getLogger() est beaucoup plus cher que le idem de JUL. (95 ms vs 0.3 ms si mon profileur est précis). Cela fait sens. SLF4J doit faire un certain temps sur la liaison de l'implémentation de journalisation sous-jacente. Cela ne m'effraie pas. 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 votre contribution:

  1. Il donne la flexibilité de choisir l'implémentation du journal au moment du déploiement.

  2. Problèmes avec le manque de flexibilité de la configuration de JUL lorsqu'il est exécuté à l'intérieur d'un serveur d'applications.

  3. 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 plus d'efforts ont été consacrés à l'optimisation sur SLF4J+Logback que sur JUL.

  4. De la Documentation. La documentation pour SLF4J est tout simplement beaucoup plus complète et précise.

  5. Flexibilité de modèle. Comme je l'ai fait les tests, je me suis fixé pour que JUL imite le modèle par défaut de Logback. Ce modèle inclut le nom du fil. Il s " avère que JUL ne peut pas le faire 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 framework de journal. Période de!

  6. La Plupart (ou de nombreux 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 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 est que je me suis vraiment énervé contre JUL après avoir travaillé un peu avec SLF4J. Je regrette toujours que ce soit comme ça avec JUL. JUL est loin d'être parfait, mais fait le travail. Pas tout à fait assez bien. La même chose peut être dite à propos de Properties à titre d'exemple, mais nous ne pensons pas à abstraire cela afin que les gens puissent brancher leur propre bibliothèque de configuration et ce que vous avez. Je pense que la raison en est que Properties vient juste au-dessus de la barre alors que le contraire est vrai pour JUL d'aujourd'hui ... et dans le passé il est arrivé à zéro, car il n'existait pas.

Author: peterh, 2012-07-06

5 answers

Disclaimer : Je suis le fondateur des projets log4j, SLF4J et logback.

Il y a des raisons objectives de préférer SLF4J. D'une part, il accorde à l'utilisateur final la liberté de choisir le framework de journalisation sous-jacent. De plus, les utilisateurs avertis ont tendance à préférer logback qui offre des capacités au-delà de log4j, j. u. l prenant beaucoup de retard. J. u. l en termes de fonctionnalités peut être suffisant pour certains utilisateurs, mais pour beaucoup d'autres, ce n'est tout simplement pas le cas. En un mot, si la journalisation est importante pour vous, vous voudriez utiliser SLF4J avec logback comme implémentation sous-jacente. Si la journalisation est sans importance, j. u. l est bien.

Cependant, en tant que développeur oss, vous devez prendre en compte les préférences de vos utilisateurs et pas seulement les vôtres. Il s'ensuit que vous devriez adopter SLF4J non pas parce quevous êtes convaincu que SLF4J est meilleur que j. u. l mais parce que la plupart des développeurs Java actuellement (juillet 2012) préfèrent SLF4J comme API de journalisation. Si finalement vous décidez de ne pas se soucier de populaires avis, considérer les faits suivants:

  1. ceux qui préfèrent j. u. l le font par commodité car j. u. l est livré avec le JDK. À ma connaissance, il n'y a pas d'autres arguments objectifs en faveur de j. u. l.
  2. votre propre préférence pour j. u. l est juste cela, une préférence.

Ainsi, tenir des "faits durs" au-dessus de l'opinion publique, bien qu'apparemment courageux, est une erreur logique dans ce cas.

Si toujours pas convaincu, JB Nizet fait une argument supplémentaire et puissant:

Sauf que l'utilisateur final aurait déjà pu faire cette personnalisation pour son propre code, ou une autre bibliothèque qui utilise log4j ou logback. j.u.l est extensible, mais devant étendre logback, j. u. l, log4j et Dieu seulement sait quel autre cadre de journalisation car il utilise quatre bibliothèques qui utiliser quatre frameworks de journalisation différents est fastidieux. En utilisant SLF4J, vous permettez-lui de configurer les frameworks de journalisation qu'il veut, pas celui vous avez choisi. Rappelez-vous qu'un projet typique utilise des myriades de les bibliothèques, et pas seulement les vôtres.

Si pour une raison quelconque vous détestez l'API SLF4J et que son utilisation évitera le plaisir de votre travail, alors optez pour j. u. l. Après tout, il existe des moyens de rediriger j. u. l vers SLF4J.

En passant, la paramétrisation de j. u. l est au moins 10 fois plus lente que celle de SLF4J, ce qui finit par faire une différence notable.

 165
Author: Ceki, 2017-05-23 12:02:46
  1. java.util.logging a été introduit dans Java 1.4. Il y avait des utilisations pour la journalisation avant cela, c'est pourquoi de nombreuses autres API de journalisation existent. Ces API étaient très utilisées avant Java 1.4 et avaient donc un excellent marketshare qui ne tombait pas seulement à 0 lors de la sortie de 1.4.

  2. JUL n'a pas commencé si bien, beaucoup de choses que vous avez mentionnées étaient bien pires en 1.4 et ne se sont améliorées qu'en 1.5 (et je suppose que dans 6 aussi, mais je ne suis pas trop sûr).

  3. JUL n'est pas bien adapté pour plusieurs applications avec des configurations différentes dans la même JVM (pensez à plusieurs applications Web qui ne devraient pas interagir). Tomcat doit sauter à travers quelques cerceaux pour que cela fonctionne (ré-implémenter efficacement JUL si je l'ai bien compris).

  4. Vous ne pouvez pas toujours influencer le cadre de journalisation utilisé par vos bibliothèques. Par conséquent, l'utilisation de SLF4J (qui n'est en fait qu'une couche d'API très mince au-dessus des autres bibliothèques) aide à garder une image quelque peu cohérente de l'ensemble monde de journalisation (vous pouvez donc décider du cadre de journalisation sous-jacent tout en ayant toujours la journalisation de la bibliothèque dans le même système).

  5. Les Bibliothèques ne peuvent pas facilement changer. Si une version précédente d'une bibliothèque utilisait logging-library-X, elle ne peut pas facilement passer à logging-library-Y (par exemple JUL), même si cette dernière est clairement superieuse: tout utilisateur de cette bibliothèque devrait apprendre le nouveau framework de journalisation et (au moins) reconfigurer leur journalisation. C'est un grand non-non, surtout quand il n'apporte aucun gain apparent à la plupart des gens.

Cela dit, je pense que JUL est au moins une alternative valable aux autres frameworks de journalisation de nos jours.

 26
Author: Joachim Sauer, 2012-07-09 08:37:43

À mon humble avis, le principal avantage d'utiliser une façade de journalisation comme slf4j est que vous laissez l'utilisateur final de la bibliothèque choisir l'implémentation de journalisation concrète qu'il souhaite, plutôt que d'imposer votre choix à l'utilisateur final.

Peut-être qu'il a investi du temps et de l'argent dans Log4j ou LogBack (formateurs spéciaux, appenders, etc.) et préfère continuer à utiliser Log4j ou LogBack, plutôt que de configurer jul. Pas de problème: slf4j le permet. Est-ce un choix judicieux d'utiliser Log4j sur jul? Peut-être, peut-être pas. Mais vous n'avez pas de soins. Laissez l'utilisateur final choisir ce qu'il préfère.

 24
Author: JB Nizet, 2012-07-06 09:19:45

J'ai commencé, comme vous je soupçonne, à utiliser JUL parce que c'était le plus facile à démarrer immédiatement. Au fil des ans, cependant, j'en suis venu à souhaiter avoir passé un peu plus de temps à choisir.

Mon principal problème maintenant est que nous avons une quantité substantielle de code "bibliothèque" qui est utilisé dans de nombreuses applications et ils utilisent tous JUL. Chaque fois que j'utilise ces outils dans une application de type service Web, la journalisation disparaît ou va dans un endroit imprévisible ou étrange.

Notre solution était d'ajouter un façade au code de la bibliothèque qui signifiait que les appels de journal de la bibliothèque ne changeaient pas mais étaient redirigés dynamiquement vers tout mécanisme de journalisation disponible. Lorsqu'ils sont inclus dans un outil POJO, ils sont dirigés vers JUL, mais lorsqu'ils sont déployés en tant qu'application Web, ils sont redirigés vers LogBack.

Notre regret - bien sûr - est que le code de la bibliothèque n'utilise pas de journalisation paramétrée, mais cela peut maintenant être modifié au fur et à mesure des besoins.

, Nous avons utilisé slf4j pour construire la façade.

 4
Author: OldCurmudgeon, 2012-07-06 13:42:03

J'ai couru juil contre slf4j-1.7.21 sur logback-1.1.7, sortie sur un SSD, Java 1.8, Win64

Jul a couru 48449 ms, logback 27185 ms pour une boucle de 1M.

Encore, un peu plus de vitesse et une API un peu plus agréable ne vaut pas 3 bibliothèques et 800K pour moi.

package log;

import java.util.logging.Level;
import java.util.logging.Logger;

public class LogJUL
{
    final static Logger logger = Logger.getLogger(LogJUL.class.getSimpleName());

    public static void main(String[] args) 
    {
        int N = 1024*1024;

        long l = System.currentTimeMillis();

        for (int i = 0; i < N; i++)
        {
            Long lc = System.currentTimeMillis();

            Object[] o = { lc };

            logger.log(Level.INFO,"Epoch time {0}", o);
        }

        l = System.currentTimeMillis() - l;

        System.out.printf("time (ms) %d%n", l);
    }
}

Et

package log;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogSLF
{
    static Logger logger = LoggerFactory.getLogger(LogSLF.class);


    public static void main(String[] args) 
    {
        int N = 1024*1024;

        long l = System.currentTimeMillis();

        for (int i = 0; i < N; i++)
        {
            Long lc = System.currentTimeMillis();

            logger.info("Epoch time {}", lc);
        }

        l = System.currentTimeMillis() - l;

        System.out.printf("time (ms) %d%n", l);
    }

}
 1
Author: weberjn, 2016-11-25 13:24:59