Logging dans Java
Les développeurs, en général, et les développeurs Java en particulier ont l'habitude d'utiliser des instructions d'écriture sur la sortie standard ou la sortie d'erreur pour observer le comportement d'un programme à un endroit précis.
System.out.println(" message ") et System.err.println(" message ") sont deux instructions très utilisées en langage Java. Ce genre d'instructions, même en permettant de trouver des erreurs, complique le cycle de développement. Il faut penser à effacer ces instructions quand le programme est fini. En cas de changement de code les placer à nouveau dans le code.
Une meilleure pratique consiste à utiliser le système de " Logging " disponible dans Java (JDK 1.4 et sup) ou dans des programmes séparés comme par exemple LOG4J.
Avec des techniques de " logging " il est possible d'afficher ou non des messages à volonté, la sortie est optimisée et formatée. Il est possible de diriger en même temps les messages vers plusieurs sorties, utiliser des messages spécifiques pour les phases de développement et de production.
Ce tutoriel présente le système et les techniques de " Logging " disponibles en standard dans JDK à partir de la version 1.4
La version de Java utilisée est Java 1.6 update 10
La version d'Eclipse est 3.4
Un exemple très simple
Un exemple de logging le plus simple consiste à obtenir un logger pour afficher un message et utiliser toutes les propriétés par défaut. La date, l'heure et la source de l'information sont affichées par défaut.
package fr.iipt.ka.templates;
import java.util.logging.Level;
import java.util.logging.Logger;
public class SimpleLogger {
/**
* @param args
*/
public static void main(String[] args) {
Logger logger = Logger.getLogger("logger");
logger.log(Level.INFO, "Test de logger");
}
}
Affichage :
Oct 28, 2008 4:38:32 PM fr.iipt.ka.templates.SimpleLogger main
INFO: Test de logger
Un logger dirige des messages vers des sorties ou handlers (sortie d'erreurs standard, fichiers etc. L'affichage de l'exemple précédent est dirigé vers la sortie d'erreurs par défaut.
Les messages sont sélectionnés pour l'affichage selon un niveau fixé à la fois pour le logger utilisé et pour son/ses handlers. Tous les messages au-dessus du niveau fixé sont affichés. L'exemple utilise le niveau (level) " INFO " pour ses messages. Le niveau fixé par la configuration par défaut pour les loggers et la sortie d'erreurs est " INFO " donc les messages de ce niveau et des niveaux supérieurs à " INFO " sont affichés.
Note :
Ou pour le logger :
private static final Logger logger = Logger.getLogger("nom_de_logger");
Après la déclaration de la classe
,Levels
Logger :
A chaque logger est associé un level (niveau). Le level est un seuil permettant uniquement à des messages qui ont un niveau supérieur d'être envoyer vers un Handler. Tous les messages qui ont un niveau inférieur au niveau de logger sont ignorés.
Handler :
De même à chaque Handler est associé un niveau (level) et utilisé de la même manière
Sept Levels ou (niveau) sont définis et sont en ordre décroissant
• SEVERE
• WARNING
• INFO
• CONFIG
• FINE
• FINER
• FINEST
Level par défaut :
Le level par défaut pour les loggers et les sortie d'erreurs est " INFO " . Pour FileHandler il est fixé par défaut à " ALL "
Définir un level (niveau) :
logger.setLevel(Level.FINE);
handler.setLevel(Level.FINE);
A partir de ces instructions tous les messages qui ont un niveau FINE et supérieur seront affichés
ATTENTION !!!
Il faut définir le level pour le logger et le handler
Exemple :
Afficher des messages à partir de FINE
----------------------------------------
public class SimpleLogger {
/**
* @param args
*/
public static void main(String[] args) {
Logger logger = Logger.getLogger("flogger");
logger.setLevel(Level.FINE);
ConsoleHandler ch=new ConsoleHandler();
logger.addHandler(ch);
ch.setLevel(Level.FINE);
logger.fine("Msg in fine");
}
}
,Annuler tous les messages d'un logger :
Avec une seule instruction tous les messages de n'importe quel niveau sont annulés
logger.setLevel(Level.OFF);
Exemple :
---------
public class SimpleLogger {
/**
* @param args
*/
public static void main(String[] args) {
Logger logger = Logger.getLogger("finelogger");
logger.setLevel(Level.OFF);
ConsoleHandler ch=new ConsoleHandler();
logger.addHandler(ch);
ch.setLevel(Level.FINE);
logger.fine("Msg in fine");
}
}
Note :
Dans l'exemple précédent l'instruction suivante n'a aucun effet
ch.setLevel(Level.FINE);
Note :
Avec l'instruction suivante :
logger.setLevel(Level.ALL);
Tous les messages de tous les niveaux sont affichés
,Handlers
Les handlers sont des sorties de loggers.
Dans JDK 5 des handlers disponibles :
-
StreamHandler : Les messages sont envoyés vers OutputStream
-
ConsoleHandler : Les messages sont envoyés vers System.err
-
FileHandler : Les messages sont dirigés vers un fichier
-
SocketHandler : Les messages sont envoyés vers un port TCP
-
MemoryHandler : Les messages sont envoyés à la mémoire
Note:
Par défaut logger envoie des messages vers la sortie standard d'erreurs " System.err " via " ConsoleHandler " et fixe son niveau (level) comme suite :
java.util.logging.ConsoleHandler.level=INFO
et comme formatter " SimpleFormat "
Note:
Par défaut la configuration fixe le niveau (level) de logger à INFO
Note:
Par défaut un logger envoie des messages à son handler et aux handlers de ses parents, voir plus loin.
ATTENTION !!!
Pour écrire un message " fine " par exemple il faut à la fois changer le niveau (level) pour logger et handler
,Envoyer des messages vers un fichier
Pour envoyer des messages vers un fichier au lieu (ou avec) de la sortie erreurs, il suffit de définir un handler de fichier (FileHandler) et l'ajouter au logger
try {
FileHandler fh=new FileHandler();
logger.addHandler(fh);
} catch (Exception e) {}
Note :
Sans spécifier un nom pour notre fichier le logger utilise un FileHandler par défaut. Le fichier de log aura comme nom " java0.log " ou un autre chiffre pour rendre ce fichier unique. Ce fichier est écrit dans le dossier local de l'utilisateur (sauf dans Windows 95/98/Me le fichier est placé dans la racine de disque)
Important :
Dans Eclipse le fichier n'est pas placé dans le projet en-cours
Exemple :
---------
package fr.iipt.ka.templates;
import java.io.*;
import java.util.logging.*;
public class SimpleLogger {
public static void main(String[] args) {
Logger logger = Logger.getLogger("flogger");
try {
FileHandler fh=new FileHandler();
logger.addHandler(fh);
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
,Spécifier un nom pour le fichier de log
En construisant un objet FileHandler, il est possible de donner un nom au fichier (avec le chemin). Dans Eclipse un fichier sans chemin est un fichier avec un chemin implicite dans le projet en-cours.
Exemple :
---------
package fr.iipt.ka.templates;
import java.io.IOException;
import java.util.logging.*;
public class SimpleLogger {
public static void main(String[] args) {
Logger logger = Logger.getLogger("flogger");
try {
FileHandler fh=new FileHandler("myLog.txt");
logger.addHandler(fh);
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
,Rotation de fichiers
Avec " FileHandler " il est possible d'envoyer des messages vers plusieurs fichiers en rotation. En claire si un fichier est plein la sortie est dirigée vers le prochain fichier dans la série. Quand le dernier fichier est plein (selon le nombre spécifié de fichiers), le premier fichier est réutilise.
Pour le FileHandler suivant :
-
Les noms des fichiers sont : MonLog0.txt, MonLog1.txt et MonLog2.txt.
-
La taille de fichiers est fixée à 200 octets.
-
%h signifie dans le dossier local de l'utilisateur.
-
%g donne automatiquement un numéro aux fichiers de 0 à 3.
FileHandler fh=new FileHandler("%hMonLog%g.txt",200,3);
Exemple :
---------------
package fr.iipt.ka.templates;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
/**
* @author Kaesar ALNIJRES
*
*/
public class TestFichiers {
public static void main(String[] args) {
Logger logger=Logger.getLogger(TestFichiers.class.getName());
try {
//%h = le dossier local de l'utilisateur
//%g = Le numéro de fichiers est inséré automatiquement
FileHandler fh=new FileHandler("%hMonLog%g.txt",200,3);
fh.setFormatter(new SimpleFormatter());
logger.addHandler(fh);
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < 10; i++) {
logger.info("Ligne n " + i);
}
}
}
,Variables pour les nom de fichiers
Il existe quelques variables utilisables avec le nom du fichier dans un FileHandler
Par exemple :
FileHandler fh=new FileHandler("%h/myLog.txt");
Ecrit le fichier dans le dossier local de l'utilisateur, c’est comme si on a donné le chemin complet vers le dossier utilisateur
%h
Dossier local de l'utilisateur " %h/myLog.txt "
%t
Le dossier " tmp " du système " %t/myLog.txt "
%g
Le fichier est donné un numéro automatiquement(rotation de fichiers)
%u
Un chiffre pour avoir un fichier unique
/
Séparateur de fichiers ou dossiers
,Les méthodes logp
Cette méthode reçoit en arguments le nom de la classe de log, nom de la méthode et autres paramètres, permettant ainsi d'avoir les noms exacts de ses éléments, en cas d'optimisation de code et de modifications éventuelles de ces noms par la JVM
Exemple :
--------------
package fr.iipt.ka.templates;
import java.util.logging.Level;
import java.util.logging.Logger;
public class TestLogp {
public static void main(String[] args) {
Logger logger = Logger.getLogger(TestLogp.class.getName());
logger.logp(Level.INFO, "TestLogp", "main", "Message de main en utilisant \"logp\"");
}
}
,Le point d'entrée et sortie d'une méthode
Il est très utile pendant la phase de développement de recevoir des messages pour indiquer chaque entrée et sortie d'une méthode. Des méthodes spécifiques sont définies pour des Logger à cette fin
Les noms de ces méthodes est " entering " et " exiting " et plusieurs variantes sont disponibles
ATTENTION !!!
Le niveau par défaut pour " entering " et " exiting " est " FINER ". Il faut donc modifier le niveau (level) pour le logger, et le handler utilisés, sinon pas de messages. Les modifications sont à effectuer dans le programme ou dans le fichier de configuration.
Note :
Le message d'entrée " entering " commence par " ENTER " après l'affichage du niveau, et le message de sortie " exiting " par " RETURN "
Exemple :
---------
package fr.iipt.ka.templates;
import java.io.File;
import java.util.logging.*;
public class SimpleLogger {
private static Logger logger = Logger.getLogger("loggerEntreeSortie");
public static void main(String[] args) {
logger.setLevel(Level.FINER);
ConsoleHandler ch=new ConsoleHandler();
logger.addHandler(ch);
ch.setLevel(Level.FINER);
//appler lireFichier()
lireFichier(new File("fichier.txt"),true);
}
private static String lireFichier(File fichier,boolean ajouter)
{
logger.entering(SimpleLogger.class.getName(), "lireFichier",new Object[]{fichier,ajouter});
System.out.println("\n\nLe corps de la méthode ...\n\n");
String s="";
for(int i=0;i<10;i++)
s+="\n"+i;
//La méthode retourne le String " s "
logger.exiting(SimpleLogger.class.getName(), "lireFichier", s);
return s;
}
}
Affichage :
---------------
Nov 1, 2008 11:47:36 AM fr.iipt.ka.templates.SimpleLogger lireFichier
FINER: ENTRY fichier.txt true
Le corps de la méthode ...
Nov 1, 2008 11:47:36 AM fr.iipt.ka.templates.SimpleLogger lireFichier
FINER: RETURN
0
1
2
3
4
5
6
7
8
9
,Formatters :
-
Les formatters sont chargés de formater les messages.
-
Avec chaque handler est associé un formatter.
Deux formatters définis par défaut :
-
SimpleFormatter: Simple messages avec date et temps
-
XMLFormatter : Messages au format XML
Le formatter à utiliser est à spécifier :
-
Avec la méthode setFormatter de Handler
-
Dans le fichier de propriétés " JRE/lib/logging.properties ".Le formatter spécifié dans ce fichier est utilisé par défaut et n'a pas besoin de " setFormatter "
-
Dans un fichier personnalisé de propriétés.
Note :
SimpleFormatter est le format par défaut de " ConsoleHandler "
XMLFormatter est le format par défaut de " FileHandler "
Exemple SimpleFormatter :
---------------------------
package fr.iipt.ka.templates;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
/**
* @author Kaesar ALNIJRES
*
*/
public class TestFichiers {
public static void main(String[] args) {
Logger logger=Logger.getLogger(TestFichiers.class.getName());
try {
FileHandler fh=new FileHandler("simpleFormatterLog.txt");
fh.setFormatter(new SimpleFormatter());
logger.addHandler(fh);
logger.info("Message en utilisant Formatter");
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Affichage : SimpleFormatterLog.txt
-------------------------------------
Oct 31, 2008 6:59:46 PM fr.iipt.ka.templates.TestFichiers main
INFO: Message en utilisant SimpleFormatter
Exemple XMLFormater :
----------------------
package fr.iipt.ka.templates;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
/**
* @author Kaesar ALNIJRES
*
*/
public class TestFichiers {
public static void main(String[] args) {
Logger logger=Logger.getLogger(TestFichiers.class.getName());
try {
FileHandler fh=new FileHandler("XMLFormaterLog.txt");
logger.addHandler(fh);
logger.info("Message en utilisant XML Formatter");
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Affichage XMLFormatterLog.txt
------------------------------
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
dtd">
2008-10-31T19:21:21
1225477281668
0
fr.iipt.ka.templates.TestFichiers
INFO
fr.iipt.ka.templates.TestFichiers
main
10
Message en utilisant XML Formatter
,Formatter Personnalisé
Chaque Handler doit avoir un formatter (un format pour la sortie)
Les deux Formatters définis par défaut SimpleFormatter et XMLFormatter sont des enfants de la classe " Formatter ". Il est possible donc de définir son propre " Formatter " en implantent la méthode " format ". Cette méthode retourne une chaîne (String), les données à mettre dans la sortie. Cette méthode reçoit un " LogRecord ", un enregistrement contenant les commandes de loggers vers les Handlers ou sorties et des informations sur le Logger.
Note :
Le Formatter d'exemple est attaché au " ConsoleHandler " avec la méthode " setFormatter "
Note:
Une autre façon pour attacher le Formatter au " ConsoleHandler " ou un autre Handler est de modifier le fichier " JRS/lib/logging.properties " comme suite en mettant en commentaire, le formatter par défaut et en ajoutant le formatter TestFormatter :
#java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.ConsoleHandler.formatter = fr.iipt.ka.templates.TestFormatter
Exemple d'un formatter très simple
--------------------------------
package fr.iipt.ka.templates;
import java.util.logging.*;
/**
* @author Kaesar ALNIJRES
*
*/
public class TestFormatter extends Formatter{
public String format(LogRecord record) {
return
"Formatter perso"+'\n'+
"====================="+'\n'+
"Level : " + record.getLevel() + '\n' +
"LoggerName : " + record.getLoggerName() + '\n' +
"Message : " + record.getMessage() + '\n'+
"Classe : " + record.getSourceClassName() + '\n' +
"Méthode : " + record.getSourceMethodName()+"\n\n";
}
}
Exemple d'utilisation :
-----------------------
package fr.iipt.ka.templates;
import java.util.logging.*;
public class SimpleLogger {
/**
* @param args
*/
public static void main(String[] args) {
Logger logger = Logger.getLogger("finelogger");
logger.setLevel(Level.FINE);
ConsoleHandler ch=new ConsoleHandler();
ch.setFormatter(new TestFormatter());
logger.addHandler(ch);
ch.setLevel(Level.FINE);
Logger loggerEnfant = Logger.getLogger("finelogger.enfant");
logger.fine("Logger : -->Msg niveau fine\n");
loggerEnfant.fine("Logger : -->Msg niveau fine\n");
}
}
Affichage :
------------
Formatter perso
=====================
Level : FINE
LoggerName : finelogger
Message : Logger : -->Msg niveau fine
Classe : fr.iipt.ka.templates.SimpleLogger
Méthode : main
Formatter perso
=====================
Level : FINE
LoggerName : finelogger.enfant
Message : Logger : -->Msg niveau fine
Classe : fr.iipt.ka.templates.SimpleLogger
Méthode : main
,Hiérarchie de loggers
Chaque logger enfant hérite les propriétés de son parent et utilise son Handler
,Hiérarchie de loggers suite
Logger logger = Logger.getLogger("finelogger");
est le parent de
Logger loggerEnfant = Logger.getLogger("finelogger.enfant");
Résultat en fixant le niveau Logger/Handler à " FINE " pour fineLogger, fineLogger.enfant aura aussi " FINE " comme niveau
Note :
La relation parent/enfant est à l'image de packages de Java et sont décrit à l'aide d'un point
Note:
Si aucun niveau ou level n’est fixé pour un logger ou son parent tous les parents sont inspectés en montant et jusque " root " pour trouver un niveau (le niveau pour root est INFO)
Exemple :
---------
package fr.iipt.ka.templates;
import java.util.logging.*;
public class SimpleLogger {
public static void main(String[] args) {
Logger logger = Logger.getLogger("finelogger");
logger.setLevel(Level.FINE);
ConsoleHandler ch=new ConsoleHandler();
logger.addHandler(ch);
ch.setLevel(Level.FINE);
Logger loggerEnfant = Logger.getLogger("finelogger.enfant");
//niveau Logger et Handler hérités de son parent
loggerEnfant.fine("Logger : "+loggerEnfant.getName()+"-->Msg niveau fine\n");
loggerEnfant.fine("Le parent de loggerEnfant est : "+loggerEnfant.getParent().getName()+"\n");
}
}
Affichage :
-----------
Oct 30, 2008 10:33:29 AM fr.iipt.ka.templates.SimpleLogger main
FINE: Logger : finelogger.enfant-->Msg niveau fine
Oct 30, 2008 10:33:29 AM fr.iipt.ka.templates.SimpleLogger main
FINE: Le parent de loggerEnfant est : finelogger
,Hiérarchie de loggers suite 2
Chaque logger ayant terminé l'envoi de ses messages vers son Handler envoie des messages vers le handler de son parent
Dans l'exemple suivant le niveau pour le deuxième message de loggerEnfant utilise la méthode " info " pour envoyer le message aussi vers le handler root (le niveau par défaut pour le root est " INFO ". Maintenant le dernier message est affiché deux fois, une sur le handler parent de loggerEnfant et l'autre sur le handler de root
Exemple :
---------
package fr.iipt.ka.templates;
import java.util.logging.*;
public class SimpleLogger {
public static void main(String[] args) {
Logger logger = Logger.getLogger("finelogger");
logger.setLevel(Level.FINE);
ConsoleHandler ch=new ConsoleHandler();
logger.addHandler(ch);
ch.setLevel(Level.FINE);
Logger loggerEnfant = Logger.getLogger("finelogger.enfant");
//niveau Logger et Handler hérités de son parent
loggerEnfant.fine("Logger : "+loggerEnfant.getName()+"-->Msg niveau fine\n");
//info a un niveau sup au niveau FINE donc affichage
loggerEnfant.info("Le parent de loggerEnfant est : "+loggerEnfant.getParent().getName()+"\n");
}
}
L'affichage est comme suite :
------------------------------
Oct 30, 2008 10:24:13 AM fr.iipt.ka.templates.SimpleLogger main
FINE: Logger : finelogger.enfant-->Msg niveau fine
Oct 30, 2008 10:24:13 AM fr.iipt.ka.templates.SimpleLogger main
INFO: Le parent de loggerEnfant est : finelogger
Oct 30, 2008 10:24:13 AM fr.iipt.ka.templates.SimpleLogger main
INFO: Le parent de loggerEnfant est : finelogger
,Propriétés de logging :
Par défaut Java utilise des propriétés pour ses loggers, handlers, filters etc.
Le fichier contenant les propriétés est dans le dossier d’installation de JRE
chemin_vers_JRE/lib/logging.properties
Note :
Dans ce fichier de propriétés :
Handlers si plusieurs, sont séparés par virgule " , "
.level Le seuil pour un logger
.level préfixé par un point " . " est le niveau ou level pour un
logger racine (root).
Note :
Essayer de modifier le fichier de configuration en utilisant :
System.setProperty("java.util.logging.config.file", file)
Dans " main " ne donne rien, car LogManager est initialisé au démarrage de JVM
Note:
En changeant le niveau pour logger et handler dans le fichier de configuration vers " FINE " par exemple on peut recevoir des messages pendant le développement. Quand le programme est terminé on peut modifier le niveau vers " WARNING "
,Modifier les propriétés :
Plusieurs méthodes sont disponibles pour modifier les propriétés utilisées dans le système de logging :
-
Modifier les propriétés dans le fichier de configurations
-
Ecrire un fichier de propriétés et indiquer à la JVM de l'utiliser
java -Djava.util.logging.config.file=configFile MainClass
-
Modifier des propriétés d'une façon dynamique dans le programme
-
java.util.logging.config.class pointe vers un LogManager(responsable de lire ses configurations)
,Fichier de configuration Personnalisé
Parmi les avantages énormes du système de logging la possibilité d'utiliser un/plusieurs fichiers de configuration pour les diverses phases de vie d'un programme. En autorisant comme dans l'exemple suivant la plupart des messages en cycle de développement et en n'autorisant que ceux destinés à l'utilisateur final dans la phase de production.
Exemple : Fichier de configuration :
############################################################
# ka.properties
# Fichier personnalisé pour les configuration de logging
#
# Utilisation :
# java -Djava.util.logging.config.file=ka.properties
############################################################
# Utilise la sortie erreur standard et sortie fichier
handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
# Le niveau de tous les loggers est FINER
.level= FINER
############################################################
# CONFIG pour les handlers
############################################################
# les fichiers de logs auront comme noms ka0.log, ka1.log, 2 fichiers en rotation et seront #dans le dossier local de l'utilisateur, taille
# 50000, et utilisent SimpleFormatter
java.util.logging.FileHandler.pattern = %h/ka%g.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 2
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.ConsoleHandler.level = FINER
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
Utilisation du fichier :
-
A partir de la ligne de commande :
java -Djava.util.logging.config.file=Chemin_vers_le_fichier.properties MainClass
-
Dans Eclipse :
Un clic droit sur le fichier.java (à exécuter) -> " Run As " -> " Run Configurations " -> un clic sur l'onglet " Arguments " -> Entrer dans la zone " VM Arguments " la ligne suivante :" -Djava.util.logging.config.file=/home/kas/ka.properties "
Note :
/home/kas/ka.properties est le nom du fichier de configuration avec son chemin
Note :
Dans le fichier d'exemple le niveau est modifié pour le root. Il est aussi possible de ne modifier que le niveau d'un logger spécifique en suffixant son nom avec " .level "
fr.iipt.ka.templates.SimpleLogger.level=FINER
,LogManager
Tout le système de logging pour une application est contrôlé par une instance de LogManger ;
Loggers, propriétés utilisées par les handlers
Il est possible avec un LogManager d'obtenir des informations détaillées concernant les loggers et leurs propriétés
Avoir des informations sur les loggers
getLoggerNames() de LoggerManager retourne une Enumetation, les noms de tous les logger actifs, y compris parents et root
getLevel() de Logger le niveau utilisé dans le logger
getParent() de Logger le parent du logger
Exemple :
System.out.println() est utilisée au lieu de logger pour limiter l'interférence.
-------------------------------
package fr.iipt.ka.templates;
import java.util.Enumeration;
import java.util.logging.*;
/**
* @author Kaesar ALNIJRES
*
*/
public class InformationDeLoggers {
public static void main(String[] args) {
Logger logger = Logger.getLogger("finelogger");
logger.setLevel(Level.FINE);
ConsoleHandler ch=new ConsoleHandler();
logger.addHandler(ch);
ch.setLevel(Level.FINE);
//+++++++++++++++++++++++++++++++++++++++++++++
LogManager lm = LogManager.getLogManager();
Enumeration nomsDeLoggers = lm.getLoggerNames();
System.out.println("***Informations***");
// For each logger: show name, level, handlers etc.
while (nomsDeLoggers.hasMoreElements()) {
String nomLogger = (String)nomsDeLoggers.nextElement();
Logger logger4Informations = lm.getLogger(nomLogger);
System.out.println("-----------------------");
System.out.println("Nom : ["+nomLogger+"]");
System.out.println("Level : " + logger.getLevel());
Logger parent = logger4Informations.getParent();
System.out.print("Parent : ");
if (parent == null)
System.out.println("Le root n'a pas de parent");
else if(parent.getName().equals(""))
System.out.println("Root");
else
System.out.println(""+parent.getName());
// Les handlers du logger
Handler[] handlers = logger.getHandlers();
for(Handler handler: handlers)
{
System.out.println("Handler : "+handler.getClass().getName() );
System.out.println("level par le handler: " + handler.getLevel());
}
}
}
}
Affichage :
-----------
***Informations***
-----------------------
Nom : [finelogger]
Level : FINE
Parent : Root
Handler : java.util.logging.ConsoleHandler
level par le handler: FINE
-----------------------
Nom : [global]
Level : FINE
Parent : Root
Handler : java.util.logging.ConsoleHandler
level par le handler: FINE
-----------------------
Nom : []
Level : FINE
Parent : Le root n'a pas de parent
Handler : java.util.logging.ConsoleHandler
level par le handler: FINE
,Localization :
C'est la possibilité de présenter un programme en plusieurs langues (ici les messages de logging)
L'internationalisation de programmes en Java " i18n " est un sujet très vaste. Ici, je présente très brièvement les étapes pour sortir des messages en anglais et en français :
-
Création de deux fichiers à mettre avec les fichiers .class du programme :
-
logmessages_en.properties
-
logmessages_fr.properties
-
Le format des fichiers :
mot_clé=valeur
Exemple Pour le fichier en anglais :
readingFile=I m reading the file ! Please wait.
writingFile=I m writing the file ...Exemple le même fichier en français
readingFile=En train de lire le fichier ! Patience.
writingFile=Ecrire dans le fichier
-
Obtenir une instance de logger avec le nom d’un resourceBundle comme suite :
Logger logger=Logger.getLogger(" nom_logger ", "fr.iipt.ka.templates.logmessages" -
Utilier des mots clés dans des messages log et non des chaînes
Par exemple " readingFile " est un mot clé défini dans des fichiers de mapping :logger.info(" readingFile ");
-
Selon le local utilisé par défaut le message est affiché en français ou anglais
Note :
Il est possible de spécifier un local à utiliser pour un programme comme suite :
java -Duser.language=FR MainClass
Note :
Dans Eclipse " -Duser.language=FR " dans " Run As -> Run configurations -> Arguments -> JVM arguments "
Note :
Utiliser logger.log(level,msg) au lieu de logger.level(msg) permet d'afficher des messages traduits y compris les niveaux de logger
Exemple logging en français ou en anglais :
---------------------------------------------------------------
package fr.iipt.ka.templates;
import java.util.logging.Level;
import java.util.logging.Logger;
public class LocalizationLogger {
/**
* @param args
*/
public static void main(String[] args) {
Logger logger=Logger.getLogger(LocalizationLogger.class.getName(), "fr.iipt.ka.templates.logmessages");
logger.log(Level.SEVERE,"readingFile");
}
}
Affichage, langue et local en français :
-----------------------------------------
1 nov. 2008 19:30:05 fr.iipt.ka.templates.LocalizationLogger main
GRAVE: En train de lire le fichier ! Patience.
Affichage, langue et local en anglais :
---------------------------------------
Nov 1, 2008 7:42:13 PM fr.iipt.ka.templates.LocalizationLogger main
SEVERE: I'm reading the file ! Please wait.
,ConsoleHandler
-Par défaut un logger envoie des messages vers un " ConsoleHandler " qui utilise System.err pour l’affichage.
-Il utilise par défaut " SimpleFormatter "
-Son niveau par défaut est "Level.INFO "
Il est possible d'installer un nouveau " ConsoleHandler " et n'utiliser pas le " ConsoleHandler " défini par défaut.
Note :
Chaque logger affiche des messages via son handler et les handlers de ses parents et il y a déjà un ConsoleHandler défini par défaut.
logger.setUseParentHandlers(false);
Permet d’annuler l’utilisation de handler des parents.
Exemple :
----------
package fr.iipt.ka.templates;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
public class DeuxConsoleHandler {
/**
* @param args
*/
public static void main(String[] args) {
Logger logger=Logger.getLogger(DeuxConsoleHandler.class.getName());
logger.setLevel(Level.FINE);
Handler handler=new ConsoleHandler();
handler.setLevel(Level.FINE);
logger.addHandler(handler);
logger.setUseParentHandlers(false);
logger.info("message new console");
}
}
,FileHandler
-Les messages de loggers sont envoyés vers un fichier simple ou plusieurs fichiers en rotation
-Par défaut XMLFormatter est utilisé
-Le niveau par défaut est " Level.ALL "
-L'encodage utilisée est le l'encodage de caractères sur le système
-Par défaut pas de rotation de fichiers
Variables à utiliser dans les noms de fichiers
%h
Dossier local de l'utilisateur " %h/myLog.txt "
%t
Le dossier " tmp " du système " %t/myLog.txt "
%g
Le fichier est donné un numéro automatiquement dans des rotations
%u
Un chiffre pour avoir un fichier unique
/
Séparateur de fichiers ou dossiers
Note :
Normalement la variable %u est remplacé par un " 0 "
Si un processus essaye d'ouvrir un fichier en-cours d'utilisation par un autre processus le zéro " 0 " est remplacé par " 1 " etc.
Note :
Envoyer des messages vers FileHandler par défaut :
FileHandler handler = new FileHandler();
logger.addHandler(handler);
Note :
Pour envoyer plusieurs sorties d'applications vers un seul fichier, utiliser " append " dans le fichier log.properties, ou en utilisant le constructeur :
FileHandler
(
String
pattern, boolean append)
,Il reste encore des choses ?
Le système de logging a encore beaucoup de fonctionnalités non abordées dans ce tutoriel, SocketHandler, utiliser des arguments dans des messages, utiliser Jconsole, instrumentation, pour ne citer que quelques exemples.
Ajouter un commentaire