Publié par

Il y a 5 mois -

Temps de lecture 4 minutes

Flogger : le logger fluent de Google pour Java

Qui pensait que le logging en Java pouvait encore évoluer ? C’est pourtant ce qu’a réussi à faire Google avec Flogger : leur framework de logging pour Java.

Après les classiques SLF4J ou Apache Log4j, découvrons ce qu’apporte cette API de logging.

Présentation

Flogger est une API de logging fluent pour Java qui se veut auto-documentée, performante et extensible.

Le logging avec Flogger ressemble à ça :

private static final FluentLogger LOGGER = FluentLogger.forEnclosingClass();

public void updateUser(User user) {
    try {
        ...
    } catch (Exception e) {
        LOGGER.atSevere().withCause(e).log("Error while updating user %s", user.getEmail());
    }
}

Pour ajouter la bibliothèque à vos dépendances, vous aurez besoin de com.google.flogger:flogger: et com.google.flogger:flogger-system-backend:.

Avantages

Lisibilité

Si l’on considère le logger fourni avec le JDK, JUL (pour java.util.logging, et non pas l’artiste Julien Mari), celui-ci n’expose que quelques méthodes, dont log, qui est surchargée plusieurs fois avec des paramètres différents. Cela rajoute une confusion sur ce qui doit être passé en paramètre :

LOGGER.log(Level.INFO, "Hello world {0}", name);

SLF4J quant à lui propose différentes méthodes pour les différents niveaux de log : debug, info, error, … Mais l’ambiguïté reste tout de même présente :

try {
    ...
} catch (Exception e) {
    LOGGER.error("Error", e); // Pas besoin du placeholder {}, la signature de la méthode est : error(String msg, Throwable t)
    LOGGER.error("Error - code={} - {}", param, e); // Le placeholder {} est nécessaire pour logger la stack trace : error(String format, Object arg1, Object arg2)
}

Et voici enfin la syntaxe proposée par Flogger :

LOGGER.atInfo().withCause(exception).log("Log message with: %s", argument);

Le formatage des messages se fait grâce aux spécificateurs de Java : %s , %d , %t , etc.

Flogger gère aussi le logging lorsqu’un événement arrive toutes les n fois, évitant ainsi d’entourer son log dans un if :

// Sans Flogger :
private static final AtomicInteger LOG_COUNTER = new AtomicInteger();
...
if ((LOG_COUNTER.incrementAndGet() % 100) == 0) {
  LOGGER.info("My log message {}", arg);
}

// Avec Flogger :
FLOGGER.atInfo().every(100).log("My log message %s", arg);
FLOGGER.atSevere().atMostEvery(30, SECONDS).log("My log message %s", arg);

Rapidité

Logger peut-être coûteux en performance, c’est pour cela qu’il faut faire attention aux paramètres passés aux méthodes de logging :

LOGGER.debug("Doing someting with {}", myObject); // Recommandé : toString() sera appelée si les logs en debug doivent être affichés
LOGGER.debug("Doing someting with {}", myObject.toString()); // A éviter
LOGGER.debug("Doing someting with " + myObject.toString()); // A proscrire !

Prenons ensuite la méthode Logger#info(String, Object...) de SLF4J. Elle semble être efficace, mais lorsqu’elle est appelée, Java va automatiquement instancier un nouvel Object[], et les types primitifs seront auto-boxés, et cela coûte cher en bytecode généré à la compilation. C’est pourquoi les mainteneurs de Guice et Guava ont fait le choix d’implémenter plus d’une cinquantaine de méthodes log différentes, comme par exemple :

void log(String msg, @Nullable Object p1);
void log(String msg, long p1);
void log(String msg, int p1, boolean p2);
void log(String msg, boolean p1, byte p2);
void log(
      String msg,
      @Nullable Object p1,
      @Nullable Object p2,
      @Nullable Object p3,
      @Nullable Object p4);
void log(
      String msg,
      @Nullable Object p1,
      @Nullable Object p2,
      @Nullable Object p3,
      @Nullable Object p4,
      @Nullable Object p5,
      @Nullable Object p6,
      @Nullable Object p7,
      @Nullable Object p8,
      @Nullable Object p9,
      @Nullable Object p10,
      Object... rest);
...

Le second avantage de Flogger est de proposer la prise en compte des lambdas en paramètres des logs, qui ne seront évalués que si le log doit être affiché :

LOGGER.atInfo().log("stats=%s", LazyArgs.lazy(() -> createSummaryOf(stats)));

Extensibilité

Le dernier avantage que Flogger se vante d’offrir est sa flexibilité.

Si l’on souhaite rajouter des fonctionnalités au logger pour un besoin métier particulier, comme par exemple rajouter des informations pour un utilisateur, c’est possible en implémentant une classe UserLogger héritant de l’API Flogger et en l’utilisant ainsi :

LOGGER.at(INFO).forUserId(id).log("Message: %s", param);

Malheureusement, la documentation de Flogger étant inexistante sur ce sujet, je n’ai pas pu expérimenter cette solution.

Conclusion

Flogger existe depuis un peu plus d’un an aujourd’hui et n’est qu’en version 0.4 (depuis mars 2019). Le site de l’API n’est pas encore complet, il y manque notamment de la documentation sur son utilisation, sur les différents systèmes de backend compatibles avec Flogger, ainsi que sur la customisation du logger.

D’après Google, la bibliothèque est déjà utilisée par la majorité de leurs projets en Java et leur a permis de corriger des milliers de bugs.

D’après moi, Flogger est une API à surveiller du coin de l’œil, de par son originalité.

Publié par

Commentaire

1 réponses pour " Flogger : le logger fluent de Google pour Java "

  1. Publié par , Il y a 3 mois

    Super article
    Juste un bémol sur l’exemple avec slf4j ;)
    Utiliser {} pour logger une stacktrace ne fonctionne pas ! cela va faire un toString() sur l’exception et ne logger que son message.
    c’est la raison pour laquelle il ne faut jamais faire :
    LOGGER.error(« {} », e) => pas de stacktrace
    mais plutôt
    LOGGER.error(«  », e) => stacktrace
    ou
    LOGGER.error(« Une erreur est survenue », e) => message perso + stacktrace

    si le dernier paramètre est un exception elle sera tjrs traitée comme tel.
    Avec un message paramétré ca donne
    LOGGER.error(« Une erreur est survenue à l’étape {} », step, e) => message paramétré + stacktrace

    https://www.slf4j.org/faq.html#paramException
    https://www.slf4j.org/faq.html#exception_message

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Nous recrutons

Être un Xebian, c'est faire partie d'un groupe de passionnés ; C'est l'opportunité de travailler et de partager avec des pairs parmi les plus talentueux.