Java Language
Journalisation (java.util.logging)
Recherche…
Utilisation du consignateur par défaut
Cet exemple montre comment utiliser l'API de journalisation par défaut.
import java.util.logging.Level;
import java.util.logging.Logger;
public class MyClass {
// retrieve the logger for the current class
private static final Logger LOG = Logger.getLogger(MyClass.class.getName());
public void foo() {
LOG.info("A log message");
LOG.log(Level.INFO, "Another log message");
LOG.fine("A fine message");
// logging an exception
try {
// code might throw an exception
} catch (SomeException ex) {
// log a warning printing "Something went wrong"
// together with the exception message and stacktrace
LOG.log(Level.WARNING, "Something went wrong", ex);
}
String s = "Hello World!";
// logging an object
LOG.log(Level.FINER, "String s: {0}", s);
// logging several objects
LOG.log(Level.FINEST, "String s: {0} has length {1}", new Object[]{s, s.length()});
}
}
Niveaux de journalisation
Java Logging Api a 7 niveaux . Les niveaux en ordre décroissant sont:
-
SEVERE
(valeur la plus élevée) -
WARNING
-
INFO
-
CONFIG
-
FINE
-
FINER
-
FINEST
(valeur la plus basse)
Le niveau par défaut est INFO
(mais cela dépend du système et de la machine virtuelle utilisée).
Remarque : Il existe également des niveaux OFF
(peuvent être utilisés pour désactiver la déconnexion) et ALL
(l’opportunité de OFF
).
Exemple de code pour ceci:
import java.util.logging.Logger;
public class Levels {
private static final Logger logger = Logger.getLogger(Levels.class.getName());
public static void main(String[] args) {
logger.severe("Message logged by SEVERE");
logger.warning("Message logged by WARNING");
logger.info("Message logged by INFO");
logger.config("Message logged by CONFIG");
logger.fine("Message logged by FINE");
logger.finer("Message logged by FINER");
logger.finest("Message logged by FINEST");
// All of above methods are really just shortcut for
// public void log(Level level, String msg):
logger.log(Level.FINEST, "Message logged by FINEST");
}
}
Par défaut, l'exécution de cette classe ne produira que des messages de niveau supérieur à CONFIG
:
Jul 23, 2016 9:16:11 PM LevelsExample main
SEVERE: Message logged by SEVERE
Jul 23, 2016 9:16:11 PM LevelsExample main
WARNING: Message logged by WARNING
Jul 23, 2016 9:16:11 PM LevelsExample main
INFO: Message logged by INFO
Enregistrement de messages complexes (efficacement)
Regardons un exemple de journalisation que vous pouvez voir dans de nombreux programmes:
public class LoggingComplex {
private static final Logger logger =
Logger.getLogger(LoggingComplex.class.getName());
private int total = 50, orders = 20;
private String username = "Bob";
public void takeOrder() {
// (...) making some stuff
logger.fine(String.format("User %s ordered %d things (%d in total)",
username, orders, total));
// (...) some other stuff
}
// some other methods and calculations
}
L'exemple ci-dessus semble très bien, mais de nombreux programmeurs oublient que Java VM est une machine à pile. Cela signifie que tous les paramètres de la méthode sont calculés avant d' exécuter la méthode.
Ce fait est crucial pour la connexion à Java, en particulier pour la journalisation de FINER
à des niveaux bas tels que FINE
, FINER
, FINEST
qui sont désactivés par défaut. Regardons le bytecode Java pour la méthode takeOrder()
.
Le résultat pour javap -c LoggingComplex.class
est quelque chose comme ceci:
public void takeOrder();
Code:
0: getstatic #27 // Field logger:Ljava/util/logging/Logger;
3: ldc #45 // String User %s ordered %d things (%d in total)
5: iconst_3
6: anewarray #3 // class java/lang/Object
9: dup
10: iconst_0
11: aload_0
12: getfield #40 // Field username:Ljava/lang/String;
15: aastore
16: dup
17: iconst_1
18: aload_0
19: getfield #36 // Field orders:I
22: invokestatic #47 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
25: aastore
26: dup
27: iconst_2
28: aload_0
29: getfield #34 // Field total:I
32: invokestatic #47 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
35: aastore
36: invokestatic #53 // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
39: invokevirtual #59 // Method java/util/logging/Logger.fine:(Ljava/lang/String;)V
42: return
La ligne 39 exécute la journalisation proprement dite. Tous les travaux précédents (chargement de variables, création de nouveaux objets, concaténation de chaînes dans la méthode de format
) peuvent être inutiles si le niveau de consignation est défini plus haut que FINE
(et par défaut c'est le cas). Une telle journalisation peut être très inefficace, consommant des ressources inutiles de mémoire et de processeur.
C'est pourquoi vous devriez demander si le niveau que vous souhaitez utiliser est activé.
La bonne manière devrait être:
public void takeOrder() {
// making some stuff
if (logger.isLoggable(Level.FINE)) {
// no action taken when there's no need for it
logger.fine(String.format("User %s ordered %d things (%d in total)",
username, orders, total));
}
// some other stuff
}
Depuis Java 8:
La classe Logger a des méthodes supplémentaires qui prennent un Supplier<String>
comme paramètre, qui peut simplement être fourni par un lambda:
public void takeOrder() {
// making some stuff
logger.fine(() -> String.format("User %s ordered %d things (%d in total)",
username, orders, total));
// some other stuff
}
La méthode Fournisseurs get()
- dans ce cas, le lambda - est uniquement appelée lorsque le niveau correspondant est activé et donc if
construction n'est plus nécessaire.