131 votes

Pourquoi les messages de journalisation Level.FINE ne s'affichent-ils pas ?

El JavaDocs pour java.util.logging.Level l'État :


Les niveaux, par ordre décroissant, sont les suivants :

  • SEVERE (valeur la plus élevée)
  • WARNING
  • INFO
  • CONFIG
  • FINE
  • FINER
  • FINEST (valeur la plus basse)

Source :

import java.util.logging.*;

class LoggingLevelsBlunder {

    public static void main(String[] args) {
        Logger logger = Logger.getAnonymousLogger();
        logger.setLevel(Level.FINER);
        System.out.println("Logging level is: " + logger.getLevel());
        for (int ii=0; ii<3; ii++) {
            logger.log(Level.FINE, ii + " " + (ii*ii));
            logger.log(Level.INFO, ii + " " + (ii*ii));
        }
    }
}

Sortie

Logging level is: FINER
Jun 11, 2011 9:39:23 PM LoggingLevelsBlunder main
INFO: 0 0
Jun 11, 2011 9:39:24 PM LoggingLevelsBlunder main
INFO: 1 1
Jun 11, 2011 9:39:24 PM LoggingLevelsBlunder main
INFO: 2 4
Press any key to continue . . .

Exposé du problème

Dans mon exemple, le Level a FINER Je m'attendais donc à voir deux messages pour chaque boucle. Au lieu de cela, je vois un seul message pour chaque boucle (le message Level.FINE sont manquants).

Question

Qu'est-ce qui doit changer pour que le FINE (, FINER o FINEST ) ?

Mise à jour (solution)

Merci à La réponse de Vineet Reynolds Cette version fonctionne conformément à mes attentes. Il affiche 3 x INFO messages, & 3 x FINE messages.

import java.util.logging.*;

class LoggingLevelsBlunder {

    public static void main(String[] args) {
        Logger logger = Logger.getAnonymousLogger();
        // LOG this level to the log
        logger.setLevel(Level.FINER);

        ConsoleHandler handler = new ConsoleHandler();
        // PUBLISH this level
        handler.setLevel(Level.FINER);
        logger.addHandler(handler);

        System.out.println("Logging level is: " + logger.getLevel());
        for (int ii=0; ii<3; ii++) {
            logger.log(Level.FINE, ii + " " + (ii*ii));
            logger.log(Level.INFO, ii + " " + (ii*ii));
        }
    }
}

12 votes

Il me semble que vous aurez les messages imprimés deux fois sur la console pour INFO et au-dessus : d'abord par le logger anonyme, puis par son parent, le logger global qui a aussi un ConsoleHandler réglé sur INFO par défaut. Pour désactiver le logger global, vous devez ajouter cette ligne de code : logger.setUseParentHandlers(false) ;

0 votes

Je veux juste confirmer le commentaire de mins sur les doubles. Vous obtiendrez deux sorties à moins que vous n'utilisiez .setUseParentHandlers(false) ;

0 votes

Dans votre solution, bûcheron a deux Handlers (un par défaut à INFO et un ajouté à FINE), donc logger.info("quelque chose") s'imprimerait deux fois

140voto

Vineet Reynolds Points 40529

Les enregistreurs ne font qu'enregistrer le message, c'est-à-dire qu'ils créent les enregistrements (ou les demandes d'enregistrement). Ils ne publient pas les messages vers les destinations, ce qui est pris en charge par les Handlers. Le fait de définir le niveau d'un enregistreur ne fait qu'entraîner créer les enregistrements de journal correspondant à ce niveau ou à un niveau supérieur.

Vous utilisez peut-être un ConsoleHandler (Je n'ai pas pu déduire si votre sortie est System.err ou un fichier, mais je suppose que c'est le premier), qui publie par défaut des enregistrements de journal de niveau Level.INFO . Vous devrez configurer ce gestionnaire pour qu'il publie des enregistrements de journal de niveau Level.FINER et plus, pour le résultat souhaité.

Je vous recommande de lire le Aperçu de la journalisation Java afin de comprendre la conception sous-jacente. Le guide couvre la différence entre le concept d'un Logger et d'un Handler.

Modification du niveau du gestionnaire

1. Utilisation du fichier de configuration

Le fichier de propriétés java.util.logging (par défaut, c'est le fichier logging.properties dans JRE_HOME/lib ) peut être modifié pour changer le niveau par défaut du ConsoleHandler :

java.util.logging.ConsoleHandler.level = FINER

2. Créer des gestionnaires au moment de l'exécution

Ceci n'est pas recommandé, car cela aurait pour conséquence de remplacer la configuration globale. Si vous l'utilisez dans l'ensemble de votre code, la configuration du logger risque d'être difficile à gérer.

Handler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.FINER);
Logger.getAnonymousLogger().addHandler(consoleHandler);

2 votes

Merci. Cela a fait l'affaire. Je comprends maintenant pourquoi j'étais si confus au départ. J'avais déjà travaillé avec des niveaux de journalisation, mais l'implémentation que j'avais faite à l'époque déposait simplement chaque message journalisé dans une liste qui était affichée sans tenir compte de l'élément Handler .

3 votes

Vous êtes les bienvenus. Et ouais, le design vous atteint, si quelqu'un a écrit des loggers qui ont simplement déversé des chaînes de caractères dans un fichier, une console, etc.

11 votes

Et la modification du fichier logging.properties dans la bibliothèque JRE globale est gérable ?

33voto

Sheepy Points 1538

Le pourquoi

java.util.logging possède un logger Root qui prend par défaut la valeur suivante Level.INFO et un ConsoleHandler qui lui est attaché et qui, par défaut, prend également la forme de Level.INFO . FINE est inférieur à INFO Les messages fins ne sont donc pas affichés par défaut.


Solution 1

Créez un logger pour l'ensemble de votre application, par exemple à partir du nom de votre paquet ou en utilisant [Logger.getGlobal()](http://docs.oracle.com/javase/7/docs/api/java/util/logging/Logger.html#getGlobal()) et connectez votre propre ConsoleLogger à celui-ci. Ensuite, vous pouvez soit demander au logger racine de se taire (pour éviter la duplication des messages de plus haut niveau), soit demander à votre logger de [ne pas transmettre les journaux](http://docs.oracle.com/javase/7/docs/api/java/util/logging/Logger.html#getUseParentHandlers()) à Root.

public static final Logger applog = Logger.getGlobal();
...

// Create and set handler
Handler systemOut = new ConsoleHandler();
systemOut.setLevel( Level.ALL );
applog.addHandler( systemOut );
applog.setLevel( Level.ALL );

// Prevent logs from processed by default Console handler.
applog.setUseParentHandlers( false ); // Solution 1
Logger.getLogger("").setLevel( Level.OFF ); // Solution 2

Solution 2

Vous pouvez également abaisser la barre de l'enregistreur de racine.

Vous pouvez les définir par code :

Logger rootLog = Logger.getLogger("");
rootLog.setLevel( Level.FINE );
rootLog.getHandlers()[0].setLevel( Level.FINE ); // Default console handler

Ou avec le fichier de configuration de journalisation, si vous êtes l'utiliser :

.level = FINE
java.util.logging.ConsoleHandler.level = FINE

En abaissant le niveau global, vous pouvez commencer à voir des messages provenant de bibliothèques centrales, comme certains composants Swing ou JavaFX. Dans ce cas, vous pouvez définir un Filtre sur le logger Root pour filtrer les messages ne provenant pas de votre programme.

11voto

Joe Yichong Points 433

POURQUOI

Comme mentionné par @Sheepy, la raison pour laquelle cela ne fonctionne pas est que java.util.logging.Logger possède un enregistreur Root qui prend par défaut la valeur suivante Level.INFO et le ConsoleHandler attachée à ce collecteur racine a également la valeur par défaut de Level.INFO . Par conséquent, afin de voir le FINE (, FINER o FINEST ), vous devez définir la valeur par défaut du collecteur Root et de sa fonction ConsoleHandler a Level.FINE comme suit :

Logger.getLogger("").setLevel(Level.FINE);
Logger.getLogger("").getHandlers()[0].setLevel(Level.FINE);

Le problème de votre mise à jour (solution)

Comme mentionné par @mins, vous aurez les messages imprimés deux fois sur la console pour INFO et plus : d'abord par le logger anonyme, puis par son parent, le logger Root qui possède également un fichier ConsoleHandler réglé sur INFO par défaut. Pour désactiver le logger Root, vous devez ajouter cette ligne de code : logger.setUseParentHandlers(false);

Il existe d'autres moyens d'empêcher les journaux d'être traités par le gestionnaire de console par défaut du journal Root mentionné par @Sheepy, par exemple :

Logger.getLogger("").getHandlers()[0].setLevel( Level.OFF );

Mais Logger.getLogger("").setLevel( Level.OFF ); ne fonctionnera pas car il ne bloque que le message transmis directement au logger Root, et non le message provenant d'un logger enfant. Pour illustrer comment la méthode Logger Hierarchy fonctionne, je dessine le schéma suivant :

enter image description here

public void setLevel(Level newLevel) définit le niveau de journalisation en spécifiant les niveaux de messages qui seront journalisés par cet enregistreur. Les niveaux de message inférieurs à cette valeur seront rejetés. La valeur de niveau Level.OFF peut être utilisée pour désactiver la journalisation. Si le nouveau niveau est nul, cela signifie que ce noeud doit hériter son niveau de son plus proche ancêtre avec une valeur de niveau spécifique (non nulle).

4voto

matthew Points 41

pourquoi ma journalisation java ne fonctionne pas

fournit un fichier jar qui vous aidera à comprendre pourquoi votre connexion ne fonctionne pas comme prévu. Il vous donne une liste complète des enregistreurs et des gestionnaires qui ont été installés, ainsi que les niveaux qui sont définis et à quel niveau dans la hiérarchie de l'enregistrement.

1 votes

Il s'agit d'un commentaire, pas d'une réponse.

1voto

zhen_khokh Points 36

J'ai essayé d'autres variantes, celle-ci peut être appropriée.

    Logger logger = Logger.getLogger(MyClass.class.getName());        
    Level level = Level.ALL;
    for(Handler h : java.util.logging.Logger.getLogger("").getHandlers())    
        h.setLevel(level);
    logger.setLevel(level);
// this must be shown
    logger.fine("fine");
    logger.info("info");

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X