web-dev-qa-db-fra.com

Pourquoi les messages de journalisation Level.FINE ne sont-ils pas affichés?

Les JavaDocs for Java.util.logging.Level état:


Les niveaux en ordre décroissant sont:

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

La 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 . . .

Déclaration du problème

Mon exemple définit le Level sur FINER, donc je m'attendais à voir 2 messages pour chaque boucle. Au lieu de cela, je ne vois qu'un seul message pour chaque boucle (le Level.FINE _ messages sont manquants).

Question

Que faut-il changer pour voir la sortie FINE (, FINER ou FINEST)?

Mise à jour (solution)

Grâce à réponse de Vineet Reynolds , cette version fonctionne selon mes attentes. Il affiche 3x INFO messages et 3x 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));
        }
    }
}
106
Andrew Thompson

Les enregistreurs enregistrent uniquement 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, qui sont pris en charge par les gestionnaires. Définir le niveau d'un enregistreur ne fait que créer enregistrer les enregistrements correspondant à ce niveau ou à un niveau supérieur.

Vous utilisez peut-être un ConsoleHandler (je ne peux pas en déduire si votre sortie est System.err ou un fichier, mais je suppose que c'est le premier), qui est par défaut la publication enregistrer les enregistrements du niveau Level.INFO. Vous devrez configurer ce gestionnaire pour publier les enregistrements de journal de niveau Level.FINER et plus, pour le résultat souhaité.

Je vous recommande de lire le guide Présentation de Java Logging , afin de comprendre la conception sous-jacente. Le guide couvre la différence entre le concept d'un enregistreur et d'un gestionnaire.

Modification du niveau du gestionnaire

1. Utilisation du fichier de configuration

Le fichier de propriétés Java.util.logging (par défaut, il s’agit du fichier logging.properties fichier dans JRE_HOME/lib) peut être modifié pour modifier le niveau par défaut de ConsoleHandler:

Java.util.logging.ConsoleHandler.level = FINER

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

Ceci n'est pas recommandé car cela entraînerait le remplacement de la configuration globale. Si vous utilisez ceci dans votre base de code, vous obtiendrez une configuration de consignateur impossible à gérer.

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

Le pourquoi

Java.util.logging a un enregistreur racine dont la valeur par défaut est Level.INFO, Et un ConsoleHandler qui lui est associé qui est également défini par défaut sur Level.INFO. FINE est inférieur à INFO, ainsi les messages fins ne sont pas affichés par défaut.


Solution 1

Créez un enregistreur pour l’ensemble de votre application, par exemple. à partir de votre nom de package ou utilisez Logger.getGlobal() , et connectez-y votre propre ConsoleLogger. Ensuite, demandez à l'enregistreur racine de se fermer (pour éviter la duplication des messages de niveau supérieur) ou demandez à votre enregistreur de ne transfère pas les journaux à la racine.

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 baisser la barre de l’enregistreur 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 la journalisation, si vous utilisez l’utilisez :

.level = FINE
Java.util.logging.ConsoleHandler.level = FINE

En abaissant le niveau global, vous pouvez commencer à voir les messages des bibliothèques principales, tels que certains composants Swing ou JavaFX. Dans ce cas, vous pouvez définir un Filtre sur l'enregistreur racine afin de filtrer les messages autres que ceux de votre programme.

24
Sheepy

pourquoi mon Java la journalisation 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 de ce que les enregistreurs et les gestionnaires ont été installés et quels niveaux sont définis et à quel niveau de la hiérarchie de journalisation.

4
matthew

[~ # ~] pourquoi [~ # ~]

Comme mentionné par @Sheepy, la raison pour laquelle cela ne fonctionne pas est que Java.util.logging.Logger A un enregistreur racine dont le nom par défaut est Level.INFO, Et que ConsoleHandler est également associé à cet enregistreur racine. La valeur par défaut est Level.INFO. Par conséquent, pour voir la sortie FINE (, FINER ou FINEST), vous devez définir la valeur par défaut du consignateur racine et de sa valeur ConsoleHandler. à 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, les messages seront imprimés deux fois sur la console pour INFO et au-dessus: tout d'abord par le consignateur anonyme, puis par son parent, le consignateur racine qui possède également un ConsoleHandler. réglé sur INFO par défaut. Pour désactiver le consignateur racine, vous devez ajouter cette ligne de code: logger.setUseParentHandlers(false);

Il existe d'autres moyens d'empêcher le traitement des journaux par le gestionnaire de console par défaut du consignateur racine mentionné par @Sheepy, par exemple:

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

Mais Logger.getLogger("").setLevel( Level.OFF ); ne fonctionnera pas car il bloque uniquement le message transmis directement au consignateur racine, et le message ne provient pas d'un consignateur enfant. Pour illustrer le fonctionnement de Logger Hierarchy, Je dessine le diagramme suivant:

enter image description here

public void setLevel(Level newLevel) définir le niveau de consignation en spécifiant les niveaux de message qui seront consignés par ce consignateur. Les niveaux de message inférieurs à cette valeur seront supprimés. La valeur de niveau Level.OFF peut être utilisée pour désactiver la journalisation. Si le nouveau niveau est null, cela signifie que ce nœud doit hériter de son niveau de son ancêtre le plus proche avec une valeur de niveau spécifique (non nulle).

3
Joe Yichong

Cette solution me semble meilleure en ce qui concerne la maintenabilité et la conception pour le changement:

  1. Créez le fichier de propriété de journalisation en l'incorporant dans le dossier du projet de ressource, à inclure dans le fichier jar:

    # Logging
    handlers = Java.util.logging.ConsoleHandler
    .level = ALL
    
    # Console Logging
    Java.util.logging.ConsoleHandler.level = ALL
    
  2. Chargez le fichier de propriétés à partir du code:

    public static Java.net.URL retrieveURLOfJarResource(String resourceName) {
       return Thread.currentThread().getContextClassLoader().getResource(resourceName);
    }
    
    public synchronized void initializeLogger() {
       try (InputStream is = retrieveURLOfJarResource("logging.properties").openStream()) {
          LogManager.getLogManager().readConfiguration(is);
       } catch (IOException e) {
          // ...
       }
    }
    
0
user2627331

Essayé d'autres variantes, cela peut être approprié

    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");
0
zhen_khokh

J'ai trouvé mon problème réel et cela n'a été mentionné dans aucune réponse: certains de mes tests unitaires ont provoqué l'exécution de code d'initialisation de journalisation à plusieurs reprises dans la même suite de tests, ce qui a gâché la journalisation des derniers tests.

0
Alex R