Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Utilisation de l'API SLF4J

Utilisation de l'API Log4J2 Qu'est-ce qu'un « Design Pattern » ?



Accès rapide :
Introduction
Installation de SLF4J
Installation manuelle
Installation par Maven
Produire des logs avec SLF4J
Acquisition d'un logger

Introduction

La dernière API dont je souhaite vous parler, n'est pas une API de log à proprement parler. Il s'agit plutôt d'une surcouche d'abstraction permettant à votre application de fonctionner avec une API de log quelconque. Ainsi le changement de la solution de log concrétement utilisée, n'impactera aucune ligne de code de votre application.

Liens entre les APIs java.util.logging, Log4J 2 et SLF4J

Pour comprendre son intérêt, imaginons le scénario suivant : vous développez une application Web en Java pour la gestion du personnel d'une entreprise. Pour fonctionner, cette application aura donc besoin d'un serveur Web compatible Jakarta EE (anciennement Java EE). De plus, vous souhaitez vendre l'application sans imposer à vos clients le choix d'un serveur Web. Or, les serveurs Web utilisent déjà une API de log : par exemple Tomcat utilise JUL (java.util.logging) alors que d'autres utilisent Log4J ou autre. Du coup, comment garantir que notre application tracera correctement l'activité de l'application quelle que soit l'API concrètement utilisée par le serveur Web ?

Vous l'avez compris, oui SLF4J sera dans ce cas une bonne solution : il ré-routera les demandes de log sur l'API sous-jacente. Grace à SLF4J on peut donc être complément indépendant de la solution de log retenue. Le contre-coup, c'est qu'on utilise un sur-couche, ce qui ralentit un peu les performances (mais ça peut être négligeable).

il existe d'autres API de log comparables à SLF4J et notamment JCL (Java Commons Logging).

Installation de SLF4J

Je vous propose deux solutions pour installer SLF4J : soit par le biais d'une installation manuelle, soit en utilisant l'outil Apache Maven.

Installation manuelle

Le logiciel SLF4J peut être téléchargé sur son site officiel : http://www.slf4j.org/download.html. A minima, il vous faut télécharger les deux jars suivants slf4j-api/1.7.30/slf4j-api-1.7.30.jar et slf4j-jdk14/1.7.30/slf4j-jdk14-1.7.30.jar (les numéros de versions pourront varier : je vous conseille toujours de prendre les versions les plus récentes). Le second fichier jar correspond au driver pour que SLF4J puisse utiliser l'API java.util.logging. Placez ces deux fichiers dans un dossier lib à la racine de votre projet Eclipse.

Une fois les deux JARs placés dans le projet, il ne reste plus qu'à les ajouter au CLASSPATH. Avec Eclipse, cela peut se faire en cliquant avec le bouton droit de la souris sur ces archives, puis en sélectionnant « Build Path / Add to Build Path » (ou via la boîte de dialogue « Configure Build Path »). Une fois cette étape réalisée, les deux archives doivent être visible dans les librairies référencées par le projet, comme le montre la capture d'écran ci-dessous.

Ajout des jar de SLF4J au CLASSPATH de la JVM

Il nous faut trois autres jars pour notre démo : vous les trouverez dans le ZIP de Log4J2. Vous pouvez consulter le chapitre précédent pour obtenir de plus amples informations sur le téléchargement de Log4J2. Parmi tous les fichiers jars proposés, nous avons besoin de log4j-api-2.13.3.jar, log4j-core-2.13.3.jar et log4j-slf4j-impl-2.13.3.jar. La dernière archive correspond au driver pour que SLF4J puisse utiliser l'API Log4J2. Vous pouvez les copier dans le dossier lib de votre projet.

ne rendez pas encore des trois derniers jars accessibles dans le CLASSPATH. Nous verrons cette étape un peu plus loin dans ce chapitre.

Installation par Maven

Une autre solution pour installer une librairie sur votre machine consiste à utiliser l'outil Apache Maven. Il s'agit d'un outil de construction de programme (ou outil de build) qui gère les dépendances. Nous n'avons pas encore vraiment parlé de Maven, mais nous le ferons dans un futur chapitre.

Pour ceux qui connaissent déjà Maven, voici la définition de la dépendance SLF4J, par dessus java.util.logging, pour votre projet Maven.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
<dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.30</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-jdk14</artifactId>
        <version>1.7.30</version>
    </dependency>
</dependencies>
Définition d'une dépendance sur SLF4J (par dessus java.util.logging) dans Maven

Et voici la même chose pour utiliser SLF4J par dessus Log4J2 dans Maven.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
<dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.30</version>
    </dependency>

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.13.3</version>
    </dependency>

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <groupId>org.apache.logging.log4j</groupId>
    </dependency>
    
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <groupId>org.apache.logging.log4j</groupId>
    </dependency>
</dependencies>
Définition d'une dépendance sur SLF4J (par dessus Log4J2) dans Maven
dans un premier temps, activez la première configuration Maven.

Produire des logs avec SLF4J

Pour produire des logs avec l'API SLF4J, vous devez réaliser, à minima, deux étapes :

Dans une certaine mesure, on peut dire que SLF4J et Log4J 2 se ressemblent beaucoup. Si l'on connait déjà l'une des deux APIs, apprendre à manipuler l'autre est assez simple.

Acquisition d'un logger

Pour acquérir un logger, il faut utiliser la méthode statique org.slf4j.LoggerFactory.getLogger. Par le jeu subtil de la surcharge, votre méthode d'acquisition peut accepter en paramètre plusieurs types et notamment une chaîne de caractères. Il s'agit du nom du logger : il est très important, car il servira ultérieurement à configurer ce logger. Vous pouvez mettre le nom qui vous convient. Dans l'exemple suivant, j'imagine être dans un composant logiciel « Compo1 » et j'ai donc nommé mon logger de la même manière : cela me permettra de facilement configurer les loggers de toutes les classes de ce composant logiciel.

un composant logiciel est une unité fonctionnelle qui peut regrouper une ou plusieurs classes Java. En Java, un composant logiciel est souvent associé à un package de votre application.
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
package fr.koor.samples.slf4j;

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

public class TestSLF4J {

    // Récupération de notre logger.
    private static final Logger LOGGER =  LoggerFactory.getLogger( "Compo1" );

    // Le point d'entrée du programme.
    public static void main( String [] args ) {

        // TODO: utiliser votre logger
        
    }
    
}
Fichier TestJUL.java : exemple d'instanciation d'un logger SLF4J

Certains préfèrent utiliser la signature de la méthode getLogger acceptant un objet de type java.lang.Class. Voici un exemple d'instanciation en utilisant la classe courante comme nom de logger.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
package fr.koor.samples.slf4j;

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

public class TestSLF4J {

    // Récupération de notre logger.
    private static final Logger LOGGER =  LoggerFactory.getLogger( TestSLF4J.class );

    // Le point d'entrée du programme.
    public static void main( String [] args ) {

        // TODO: utiliser votre logger
        
    }
    
}
Fichier TestJUL.java : exemple d'instanciation d'un logger SLF4J grâce à la classe courante

Je vous recommande d'utiliser cette seconde possibilité ! Effectivement, dans la configuration du moteur SLF4J, il va être possible de dire que tous les loggers commençant par un préfixe doivent appliquer telle ou telle règle. Si le préfixe utilisé correspond au nom d'un package, toutes les classes de ce package seront configurées. De plus, le mécanisme est récursif.

Vous l'aurez remarqué, le logger est, à chaque fois, défini en tant que constante privée (private static final). Afin d'améliorer les performances de votre programme, il est important de respecter cette manière de faire. En tant que membre statique, l'instanciation du logger est sa configuration n'interviendront qu'une unique fois. De plus, le fait qu'il soit marqué comme étant statique garantira que la JVM pourra placer cette instance dans un metaspace (ou le perm dans les vieilles JVMs). L'activité du garbage collector en sera donc réduite. Je vous renvoie vers les chapitres dédiés au garbage collector pour de plus amples informations.

Il est à noter que vous utilisez une méthode statique de récupération du logger (la méthode LoggerFactory.getLogger()). Pourquoi n'utilise-t-on pas un constructeur ? La raison est simple, plusieurs classes peuvent partager le même logger. Dans ce cas, on doit toujours demander le même nom de logger et la première classe qui le demande va lancer son instanciation et sa configuration. Les autres appels retourneront cette instance. Voici un exemple de code mettant en évidence ce point.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
package fr.koor.samples.log4j2;

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

public class TestSLF4J {

    // Récupérations multiples de notre logger.
    private static final Logger LOGGER1 = LoggerFactory.getLogger( "Compo1" );
    private static final Logger LOGGER2 = LoggerFactory.getLogger( "Compo1" );

    // Le point d'entrée du programme.
    public static void main( String [] args ) {

        // On fait une comparaison de pointeurs pour bien vérifier que nous 
        // avons bien deux variables qui pointent sur la même instance.
        System.out.println( LOGGER1 == LOGGER2 );       // Affiche true !
        
    }
    
}
Pour un nom de logger, vous n'aurez qu'une unique instance.

En cours de rédaction...



Utilisation de l'API Log4J2 Qu'est-ce qu'un « Design Pattern » ?