API Logging API Logging Journalisation

publicité
API Logging
Journalisation
Journalisation des
des évènements
évènements
© Philippe GENOUD
UJF
Janvier 2007
1
Journalisation
Conserver sur un support sûr des événements survenus dans un système
ou une application
Un ou plusieurs fichiers journaux (log files) générés en cours d'exécution
enregistrent des informations sur le déroulement de l'application.
Nature de l'événement
Date et heure
Gravité
Utilisateur….
Utilisés pour :
Produire des statistiques sur utilisation du système (ex: log du
serveur Apache)
Détecter des problèmes d'exécution
Reprise après pane
© Philippe GENOUD
UJF
Novembre 2008
2
Api
Api java.util.logging
java.util.logging
Java depuis la version 1.4 propose une API standard pour journaliser les
événements.
Définie dans le package java.util.logging
D'usage simple
Permet de journaliser des événements dans un fichier au format texte
ou XML
Différents niveaux de sévérité applicables aux messages journalisés
API conçue pour rendre les opérations de logging le moins coûteuses
possible
Possibilité de changer dynamiquement quels niveaux de
messages sont journalisés
Permet de faire des logging détaillés lorsque nécessaire tout en
minimisant l'impact sur l'application en mode normal
Extensible
© Philippe GENOUD
3
Novembre 2008
UJF
Api
Api java.util.logging
java.util.logging
Principale classes de l'API java.util.logging
Génère log
messages
Logger
Logger
LogManager
LogManager
Object
Object
LogRecord
LogRecord
Handler
Handler
Encapsule
contenu
d'un log
message
MemoryHandler
MemoryHandler
ConsoleHandler
ConsoleHandler
© Philippe GENOUD
Associés aux
handlers pour
formater les
LogRecords
Destination
pour les
LogRecords
StreamHandler
StreamHandler
FileHandler
FileHandler
UJF
Formatter
Formatter
SimpleFormatter
SimpleFormatter
SocketHandler
SocketHandler
Novembre 2008
XMLFormatter
XMLFormatter
<interface>
<interface>
Filter
Filter
4
Principes
Principes généraux
généraux de
de l'API
l'API Logging
Logging
Filter
À un Logger peuvent être
associés plusieurs handlers
Application
1
4
2 Logger
3
Formatter
Handler
5
Filter
7
Handler
Monde extérieur
Fichier
Console
Socket
6
Filter
Formatter
1 L'application demande à un Logger d'enregistrer une information dans le journal
2 Le Logger crée un objet LogRecord qui représente cette demande
3 Le Logger transmet éventuellement le LogRecord à un filtre pour décider si il doit être traité ou non
4 Si le filtre autorise son traitement le LogRecord est transmis à un Handler.
5 Le Handler transmet éventuellement le LogRecord à un filtre pour décider si il doit être traité ou non
6 Si le filtre autorise son traitement le LogRecord est transmis à un Formatter qui se charge de
sa mise en forme et de son éventuelle localisation
7 Le Handler publie lerésultat produit par le Formatter sur un flux d'entrée/sortie
© Philippe GENOUD
UJF
Novembre 2008
5
Création
Création d'un
d'un journal
journal
Journal représenté par un objet instance de la classe Logger
Doit être créé qu'une seule fois et partagé par les instances des
différentes classes de l'application
Accès au journal dans une classe
Référence statique pour accéder
au journal
Nom du journal
private static Logger logger =
Logger.getLogger("monLogger");
Méthode statique de la classe Logger.
© Philippe GENOUD
si plusieurs classes appellent getLogger() avec le même
nom, le journal est créé au premier appel ; pour les
prochains appels le journal n'est pas recréé, seule sa
référence est retournée .
UJF
Novembre 2008
6
Création
Création d'un
d'un journal
journal
Une fois le journal (Logger) créé il faut l'associer à un ou plusieurs
handlers qui géreront les messages (LoggerRecords)
Pour rediriger les messages du logger vers un fichier on utilise un
objet FileHandler
Création d'un file Handler qui redirigera les
LoggerRecords vers vers le fichier myLog.log
Handler fh = new FileHandler("myLog.log");
Plusieurs constructeurs permettent de spécifier le ou les fichiers utilisés et la manière dont ils le sont.
Handler fh = new FileHandler();
Système choisit lui-même le nom du fichier
Handler fh = new FileHandler("myLog.log", true);
Le fichier est repris tel quel (true) ou recrée (false)
Handler fh = new FileHandler("myLog.log", 5000, 4);
logger.addHandler(fh);
© Philippe GENOUD
Le journal est divisé en 4 fichiers de 5000 octets,
utilisés de manière cyclique,de nom myLog.log.i avec
i de 0 à 3 (motif par défaut)
Associe le FileHanlder au logger
UJF
Novembre 2008
7
Création
Création d'un
d'un journal
journal
public FileHandler(String pattern,int limit,int count,
boolean append)
pattern : motif du nom du fichier ou des fichiers à créer
limit : nombre maximum d'octets pouvant être écrits dans le fichier (0 pour pas
de limite). Si cette limite est dépassée, le FileHandler ferme le fichier, le
renomme et débute un nouveau fichier de log avec le nom original
count : nombre de fichiers à utiliser
append : le fichier est repris tel quel (true) ou recrée (false)
Lorsque ces arguments ne sont pas spécifiés dans le constructeur, une valeur par
défaut définie par le LogManager est utilisée.
pattern : %h/java%u.log
limit : 0
count : 1
append : false
© Philippe GENOUD
UJF
Novembre 2008
8
Création
Création du
du journal
journal
Des caractères spéciaux peuvent être utilisés pour définir le nom du (des)
fichier(s) de log
Caractère
Séparateur de répertoire pour la plateforme
/
Signification
%h
Répertoire de connexion de l'utilisateur (équivalent de la propriété système
"user.home")
%t
Répertoire temporaire du système
%u
Un nombre unique utilisé pour distinguer le fichier log d'autres fichiers log qui
auraient le même motif
%g
Le nombre généré automatiquement pour la rotation cyclique des fichiers
quand limit non nul et count > 1
%%
'%'
Exemple Handler fh = new FileHandler("%h/myApps.%g.log", 5000, 3);
3 fichiers logs dans le "homedir" de l'utilisateur nommés mYApps.0.log, myApps.1.log et
myApps.2.log
© Philippe GENOUD
UJF
Novembre 2008
9
Ecriture
Ecriture d'un
d'un message
message
Pour poster un message dans le journal on utilise la méthode log() de
l'objet Logger.
public void log(Level level, String msg)
Le message
Niveau du message. Si le logger est activé pour ce niveau le
message est dirigé vers tous les handlers associés au logger,
sinon le message est ignoré
Le type Level définit 7 + 2 niveaux pour les messages. Les niveaux sont
ordonnés : lorsque le Logger est activé pour un niveau tous les niveaux
supérieurs le sont également
Les niveaux dans
l'ordre décroissant
Niveau par défaut
Niveau
OFF
SEVERE
WARNING
INFO
CONFIG
FINE
FINER
FINEST
ALL
Description
Aucun niveau
Pour indiquer un problème sérieux
Pour signaler un problème potentiel
Message d'information
Configuration
Trace d'exécution
Trace d'exécution plus précise
Trace d'exécution encore plus précise
Tous les niveaux
© Philippe GENOUD
UJF
La méthode
void setLevel(Level newLevel) de
la classe Logger permet de modifier le
niveau pour lequel le journal est activé.
Exemple : pour logger tous les messages
logger.setLevel(Level.ALL)
Novembre 2008
10
Ecriture
Ecriture d'un
d'un message
message
pour simplifier l'envoi de message dans le journal il existe pour chaque
niveau une méthode qui évite d'avoir à spécifier le niveau en paramètre.
public void severe(String msg)
public void warning(String msg)
public void info(String msg)
public void config(String msg)
public void fine(String msg)
public void finer(String msg)
public void finest(String msg)
Exemple :
logger.info("connection closed");
est équivalent à
Logger.log(LEVEL.INFO,"connection closed");
© Philippe GENOUD
UJF
11
Novembre 2008
Formatage des messages
A un handler est associé un formateur qui se charge de la mise en
forme des messages avant leur écriture dans le journal
L'API logging propose deux classes de formatage de base
SimpleFormatter
XMLFormatter (défaut pour les FileHandler)
Il est possible de créer son propre "formateur" en
étendant la classe Formatter
Utilisation du message setFormatter pour
fixer le formateur d'un objet Handler
Syntaxe :
Associés aux
handlers pour
formater les
LogRecords
Formatter
Formatter
SimpleFormatter
SimpleFormatter
XMLFormatter
XMLFormatter
MyFormatter
MyFormatter
void setFormatter(Formatter newFormatter)
Exemple :
fh.setFormatter(new myFormatter());
© Philippe GENOUD
UJF
Novembre 2008
12
Formatage
Formatage des
des messages
messages
public static void main(String[] args) throws SecurityException, IOException {
Logger logger = Logger.getLogger("monLogger");
Handler fh = new FileHandler("myLog.log");
Fichier myLog.log
logger.addHandler(fh);
logger.log(Level.INFO, "coucou"); <?xml version="1.0" encoding="windows-1252" standalone="no"?>
}
<!DOCTYPE log SYSTEM "logger.dtd">
<log>
<record>
<date>2008-11-13T19:32:13</date>
<millis>1226601133062</millis>
<sequence>0</sequence>
Informations extraites <logger>monJournal</logger>
<level>INFO</level>
de l'objet LogRecord
<class>poo.cours.logging.TestAPILogging</class>
<method>main</method>
<thread>10</thread>
<message>coucou</message>
</record>
</log>
Utilisation du formateur par
défaut : XMLFormatter
public static void main(String[] args) throws SecurityException, IOException {
Logger logger = Logger.getLogger("monLogger");
Handler fh = new FileHandler("myLog.log");
Handler fh.setFormatter(new SimpleFormatter());
logger.addHandler(fh);
logger.log(Level.INFO, "coucou");
}
Fichier myLog.log
Utilisation d'un formateur
SimpleFormatter
13 nov. 2008 19:39:35 poo.cours.logging.TestAPILogging main
INFO: coucou
© Philippe GENOUD
UJF
13
Novembre 2008
Formatage
Formatage des
des messages
messages
Définition d'une nouvelle classe de Formatter
@Override
public String getHead(Handler h) {
return "debut du log\n------------\n";
}
package poo.cours.logging;
import
import
import
import
java.util.Date;
java.util.logging.Formatter;
java.util.logging.Handler;
java.util.logging.LogRecord;
public class MonFormateur extends Formatter {
}
@Override
public String format(LogRecord record) {
return "le message '" + record.getMessage() +
"' est arrivé à " +
new Date(record.getMillis()) + "\n";
}
@Override
public String getTail(Handler h) {
return "------------\nfin du log\n";
}
Écriture d'un entête et d'une
fin au journal
Formatage d'un enregistrement
public static void main(String[] args) throws SecurityException, IOException {
Logger logger = Logger.getLogger("monLogger");
Handler fh = new FileHandler("myLog.log");
Handler fh.setFormatter(new MonFormateur());
logger.addHandler(fh);
logger.log(Level.INFO, "coucou");
}
Utilisation d'un formateur
MonFormateur
Fichier myLog.log
debut du log
-----------le message 'coucou' est arrivé à Thu Nov 13 22:52:12 CET 2008
-----------fin du log
© Philippe GENOUD
UJF
Novembre 2008
14
Filtrage
Filtrage
Les filtres permettent à l'application de définir éventuelleent ses propres
règles de filtrage des LogRecords en plus des niveaux de message
Un filtre peut être associé à Logger ou à un Handler
Méthode void setFilter(Filter newFilter) des classes
Logger et Handler
Un filtre est définit en implémentant l'interface Filter.
public boolean isLoggable(LogRecord record)
Exemple :
import java.util.logging.Filter;
import java.util.logging.LogRecord;
public class myFilter implements Filter {
// décide si l’enregistrement doit être publié ou pas
public boolean isLoggable(LogRecord record) {
return record.getMessage().startsWith("DEBUG");;
}
}
© Philippe GENOUD
UJF
15
Novembre 2008
Hiérarchie
Hiérarchie des
des Loggers
Loggers
public static void main(String[] args) throws SecurityException, IOException {
Logger logger = Logger.getLogger("monLogger");
Handler fh = new FileHandler("myLog.log");
Handler fh.setFormatter(new MonFormateur());
logger.addHandler(fh);
logger.log(Level.INFO, "coucou");
}
Utilisation d'un formateur
MonFormateur
Fichier myLog.log
debut du log
-----------le message 'coucou' est arrivé à Thu Nov 13 22:52:12 CET 2008
-----------fin du log
Sur la console :
P:\CoursAPILogging\bin>java poo.cours.logging.TestAPILogging
14 nov. 2008 18:01:41 poo.cours.logging.TestAPILogging main
INFO: coucou
P:\CoursAPILogging\bin>
D'où provient cette sortie ?
Le logger spécifié dans le programme n'a
qu'un handler de type FileHandler
© Philippe GENOUD
UJF
Novembre 2008
16
Hiérarchie
Hiérarchie des
des Loggers
Loggers
Explication :
Les Loggers sont organisés en une structure arborescente
Logger racine toujours défini
– sans nom
– ConsoleHandler par défaut
Chaque
Logger a un Logger parent
Par défaut un Logger transmet les LogRecords à ses Handlers mais aussi
à son Logger parent qui les transmet à ses propres Handlers (de manière
récursive jusqu'au Logger racine)
Console
""
root Logger
14 nov. 2008 18:01:41 poo.cours.logging.TestAPILogging main
INFO: coucou
ConsoleHandler
Le Logger parent ne fait pas de filtrage ou
de contrôle de niveau du LogRecord
Fichier myLog.log
"monLogger"
debut du log
-----------le message 'coucou' est arrivé à Thu Nov 13 22:52:12
CET 2008
-----------fin du log
FileHandler
logger.log(Level.INFO, "coucou");
© Philippe GENOUD
UJF
17
Novembre 2008
Hiérarchie
Hiérarchie des
des Loggers
Loggers
La hiérarchie des loggers est construite à partir de leurs noms
Dans un nom de logger un '.' correspond à un niveau de hiérarchie
Niveau 0
Logger l1 = Logger.getLogger("l1");
Niveau 1
Logger l1_1 = Logger.getLogger("l1.1");
Niveau 2
Logger l1_2 = Logger.getLogger("l1.2");
Logger l1_1_1 = Logger.getLogger("l1.1.1");
Niveau 3
Logger racine
""
l1
l1.1
l1.2
l1.1.1
Un Logger hérite un certain nombre d'attributs de ses parents
LogingLevel : si est null, le Logger hérite du premier LoggingLevel
non null parmi ses parents
Handlers : par défaut le Logger transmet récursivement à tous
parents les LogRecord qu'il génère
ResourceBundle : pour la localisation (comme pour le LogingLevel, si
le ResourceBundle est null, il est alors hérité au travers de la
hiérarchie des loggers)
C'est joli, mais à quoi cela sert tout cela ?
© Philippe GENOUD
UJF
Novembre 2008
18
Hiérarchie
Hiérarchie des
des Loggers
Loggers
La hiérarchie des Loggers et le forwarding des LogRecords permet d'avoir
un contrôle fin sur la journalisation.
En utilisant des noms de logger qui correspondent à la hiérarchie des
packages on peut facilement contrôler le logging package par package
(voire classe par classe) ce qui peut être très utile pour une analyse fine
d'une application package package1.subPackage1;
...
public class MyClass1 {
private static Logger logger =
Logger.getLogger("package1.subPackage1.MyClass1");
...
""
}
package par défaut
Recommandation de la documentation
de l'API logging
- Nom complet (fully qualified name) de
subPackage1 subPackage2
MyClass1 …
MyClassN
la classe (une journal par classe)
- Nom du package (toutes les classes du
package utilisent le même journal)
package2
package1
…
…
LogManager.getLogManager().
getLogger("package1.subPackage1")
.setLevel(Level.ALL)
Fixe un niveau de journal ALL pour toutes les classes du
package package1.subPackage1
© Philippe GENOUD
UJF
Novembre 2008
19
Configuration
Configuration des
des journaux
journaux
La configuration par défaut du LogManager est initialisée à partir d'un
fichier de propriétés logging.properties défini dans le répertoire
lib du JRE de la JVM
Cette configuration par défaut peut être changée en modifiant ce fichier
Possibilité d'utiliser une autre fichier de configuration à l'exécution
java -Djava.util.logging.config.file=myLoggingconfigurationFile
# Global properties
handlers= java.util.logging.ConsoleHandler, java.util.logging.FileHandler
.level= INFO
#
# Handler specific properties.
#
#default file output is in user's home directory.
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
# extra control for each logger.
# set the com.xyz.foo logger to only log SEVERE messages.
com.xyz.foo.level = SEVERE
© Philippe GENOUD
UJF
Novembre 2008
20
Conclusion
Conclusion
Java.util.logging fourni une API standard pour la journalisation
Simple, flexible, efficace
Il existe d'autres alternatives qui offrent plus de fonctionnalités:
Log4j du projet Apache
http://logging.apache.org/log4j/
Extrait de la FAQ :
Why should I use log4j when JDK 1.4 already ships with a logging API?
Although both APIs are conceptually similar, the log4j API is significantly
more flexible and offers many more features, too numerous to be listed here.
Commons Logging du projet Jakarta Commons
http://commons.apache.org/logging/
jLO
http://jlo.jzonic.org/
Monolog développée par le consortium ObjectWeb
http://monolog.objectweb.org/
© Philippe GENOUD
UJF
Novembre 2008
21
Références
Références
An Introduction to the Java Logging API, Brian R. Gilstrap
http://www.onjava.com/pub/a/onjava/2002/06/19/log.html
Java Logging Technology
http://java.sun.com/javase/6/docs/technotes/guides/logging/index.html
© Philippe GENOUD
UJF
Novembre 2008
22
Téléchargement