Prérequis
Avoir des connaissances de base en Java (variables, conditions, fonctions et classes)
Connaître la structure globale d’un mod (classe principale, fonctions)
Introduction
Nous allons, dans ce tutoriel, apprendre comment bien Logger ses mods. Tout d’abord, que signifie “Logger” ?
- Logger est simplement un terme de programmation venant de l’anglais “To log”, c’est-à-dire, enregistrer. Cela permet au programmeur de débugger son programme plus efficacement. Les logs sont enregistrés dans un fichier texte et permettent aux utilisateurs du mod de transmettre au programmeur les erreurs survenues lors de l’utilisation du mod.
- Débugger : fait de déceler et corriger les bugs ou erreurs de son programme
La parenthèse de culture informatique close, nous pouvons commencer par créer notre Logger.
La classe principale du Logger
Créez tout d’abord une classe. De mon côté, je vais la nommer LoggerManager.
public class LoggerManager{
}
Jusque là, pas de problème. Nous allons ajouter un constructeur et quelques variables qui vont nous permettre de mettre en route notre Logger.
public class LoggerManager {
public static LoggerManager instance;
private Calendar calendar = Calendar.getInstance();
private Logger logger;
public LoggerManager(Logger logger, Path logFile){//Premier argument : le logger, deuxième argument : le fichier log.txt
//On instancie notre logger
this.logger = logger;
//On crée associe notre Handler au logger
this.logger.addHandler(new LoggerHandler(logFile));
//On met l'instance de la classe dans elle même (oui c'est curieux, mais ça marche)
instance = this;
}
}
Les Handler sont des objets qui se chargent de publier les messages du Logger. Vous devriez avoir une erreur, c’est normal, il nous faut créer notre propre Handler. Mais avant cela, finissons la structure de notre LoggerManager. Un petit accesseur (à insérer à la suite de notre constructeur, dans la classe) qui va permettre d’accéder au Logger depuis une autre classe :
public Logger getLogger() {
return this.logger;
}
}
Une fonction utile qui va permettre d’insérer la date et l’heure dans notre fichier log.txt :
public String getDate() {
return (calendar.get(Calendar.DAY_OF_MONTH) + "/" + calendar.get(Calendar.MONTH) + "/" + calendar.get(Calendar.YEAR)
+ "-" + calendar.get(Calendar.HOUR_OF_DAY) + ":" + calendar.get(Calendar.MINUTE) + ":" + calendar.get(Calendar.SECOND));
}
Voilà, notre LoggerManager est terminé. Nous allons maintenat pouvoir passer à notre Handler (enfin ).
La classe du Handler
Le Handler donc ^^. Je vous propose de créer une classe interne (une classe dans une classe (oui, c’est tordu, et oui on peut faire ça à l’infini)). Écrivez tout d’abord ceci dans la classe LoggerManager, au même niveau que la fonction de la date, juste en dessous) :
private class LoggerHandler extends Handler {
}
Vous allez avoir une erreur, faites les importations nécessaires (Ctrl + Shift + O). Ensuite, placez les méthodes et un constructeur à l’intérieur de cette nouvelle classe :
public LoggerHandler(Path logFile) {
}
@Override
public void publish(LogRecord record){
}
@Override
public void flush(){}
@Override
public void close() throws SecurityException{
}
Ces méthodes sont automatiquement appelées par notre Logger dés qu’un message est écrit. Elles permettent de modifier le message et d’effectuer les tâches que l’on veut dessus.
- publish() est appelée lors de la publication d’un message via le Logger
- flush() est appelée lors de la “purge” du Logger. Cela permet en fait de vider certaines ressources pour libérer de la mémoire et sauvegarder certaines informations (“vider le cache” sur Firefox par exemple). Nous ne nous en servirons pas.
- close() est appelée lors de la fermeture du Logger. Nous allons nous en servir pour fermer le fichier log.txt
Ajoutons une variable de classe qui deviendra le flux d’écriture de notre fichier log.txt.
private BufferedWriter writer = null;
Dans notre constructeur, nous allons initialiser la variable et créer le fichier s’il n’existe pas ou l’écraser, le cas échéant :
public LoggerHandler(Path logFile){
try{
if(Files.exists(logFile)){
Files.delete(logFile);//On écrase manuellement les fichiers
Files.createFile(logFile);
}
else{
Files.createFile(logFile);
}
//On initialise le flux d'écriture en UTF-8
this.writer = Files.newBufferedWriter(logFile, StandardCharsets.UTF_8);
}catch(Exception e){
System.err.println("[GRAVE] Erreur lors de la création/délétion du fichier log.");
}
}
Ensuite nous allons demander à notre Handler d’écrire le message posté dans un fichier :
try{
//On écrit le message dans le fichier log
writer.write(record.getMessage() + "<" + getDate() + "> [" + record.getLevel().getLocalizedName() + "] " + record.getMessage() + "\n");
}catch(Exception e){
//En cas de problème, on marque l'erreur
System.err.println("[GRAVE] Erreur lors de l'écriture du fichier log.");
e.printStackTrace();
}
N’oublions pas de fermer le fichier à la fin, pour éviter les erreurs lors de la lecture du fichier :
@Override
public void close() throws SecurityException{
System.out.println("<" + getDate() + "> [Infos] Fermeture des ressources…");
try{
writer.flush();
writer.close();
}catch(Exception e){}
System.out.println("<" + getDate() + "> [Infos] OK !");
}
Note : Cette méthode est appelée lors de la femeture du programme, il peut être utile de fermer les ressources d’autres classes en utilisant celle-ci !
Nous avons terminé notre Logger. Voici la classe complète au cas où je vous aurai perdu en cours de route :
LoggerManager.java :
import java.io.BufferedWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Calendar;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
public class LoggerManager {
public static LoggerManager instance;
private Calendar calendar = Calendar.getInstance();
private Logger logger;
public LoggerManager(Logger logger, Path logFile){
//On instancie notre logger
this.logger = logger;
//On crée associe notre Handler au logger
this.logger.addHandler(new LoggerHandler(logFile));
//On met l'instance de la classe dans elle même (oui c'est curieux, mais ça marche)
instance = this;
}
public Logger getLogger(){
return this.logger;
}
public String getDate(){
return (calendar.get(Calendar.DAY_OF_MONTH) + "/" + calendar.get(Calendar.MONTH) + "/" + calendar.get(Calendar.YEAR)
+ "-" + calendar.get(Calendar.HOUR_OF_DAY) + ":" + calendar.get(Calendar.MINUTE) + ":" + calendar.get(Calendar.SECOND));
}
private class LoggerHandler extends Handler{
private BufferedWriter writer = null;
public LoggerHandler(Path logFile){
try{
if(Files.exists(logFile)){
Files.delete(logFile);
Files.createFile(logFile);
}
else{
Files.createFile(logFile);
}
this.writer = Files.newBufferedWriter(logFile, StandardCharsets.UTF_8);
}catch(Exception e){
System.err.println("[GRAVE] Erreur lors de la création/délétion du fichier log.");
}
}
@Override
public void publish(LogRecord record){
try{
//On écrit le message dans le fichier log
writer.write(record.getMessage("<" + getDate() + "> [" + record.getLevel().getLocalizedName() + "] " + record.getMessage()) + "\n");
}catch(Exception e){
//En cas de problème, on marque l'erreur
System.err.println("[GRAVE] Erreur lors de l'écriture du fichier log.");
e.printStackTrace();
}
}
@Override
public void flush(){}
/**
* Lors de la fermeture du `Logger`, on ferme le fichier.
*/
@Override
public void close() throws SecurityException{
System.out.println("<" + getDate() + "> [Infos] Fermeture des ressources…");
try{
writer.flush();
writer.close();
}catch(Exception e){}
System.out.println("<" + getDate() + "> [Infos] OK !");
}
}
}
Grâce à cette classe, vous pouvez récupérer le logger depuis toutes les autres classes !
Comme je suis généreux, je vous montre comment utiliser cette classe !
Comment utiliser notre nouvelle classe
Tout d’abord, il faut initialiser le Logger. Pour ce faire, placez ce code au tout début de votre PreInit(), dans votre classe principale.
new LoggerManager(event.getModLog(), Paths.get("modid.txt"));
Remplacez le “modid” par votre modid mais laissez le “.txt”.
Maintenant, pour écrire quelque chose dans la console, vous devrez faire :
Logger logger = LoggerManager.instance.getLogger();
logger.info("Je suis un message d'information");
logger.warning("Je suis un message d'avertissement");
logger.severe("Je suis un message d'erreur");
Quand utiliser les fonctions de Logger ?
Quand vous voulez, mais surtout lorsque votre mod s’initialise, c’est là que votre mod est susceptible de planter ! Par exemple pour un fichier de configuration (exemple non fonctionnel) :
logger.info("Initialisation du fichier de configuration…");
if(Files.exists(cfg)){
Registry.loadConfig();
logger.info("Fait !");
}
else{
logger.warning("Fichier de configuration inexistant, création en cours...");
try{
Files.createFile(cfg);
if(Files.exists(cfg){
Registry.saveDefaultConfig();
logger.info("Fait !");
}
catch(Exception e){
logger.severe("Impossible de créer le fichier de configuration '" + path.toString() + "' ! Raison : " + e.getCause());
e.printStackTrace();
}
}
}
Vous pouvez constater que c’est très utile !
J’espère que ce tutoriel vous a aidé, n’hésitez pas à poster vos questions et vos problèmes sur le topic ! Sur ce,
Happy Modding !