java logging java.util.logging

java - ¿Por qué no se muestran los mensajes de registro Level.FINE?



logging java.util.logging (7)

Encontré mi problema real y no fue mencionado en ninguna respuesta: algunas de las pruebas de mi unidad estaban causando que el código de inicialización de registro se ejecutara varias veces dentro del mismo conjunto de pruebas, arruinando el registro en las pruebas posteriores.

El estado de JavaDocs para java.util.logging.Level :

Los niveles en orden descendente son:

  • SEVERE (valor más alto)
  • WARNING
  • INFO
  • CONFIG
  • FINE
  • FINER
  • FINEST (valor más bajo)

Fuente

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)); } } }

Salida

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

Planteamiento del problema

Mi ejemplo establece el Level en FINER , así que esperaba ver 2 mensajes para cada ciclo. En cambio, veo un solo mensaje para cada ciclo ( Level.FINE mensajes Level.FINE ).

Pregunta

¿Qué necesita cambiar para ver el resultado FINE (, FINER o FINER )?

Actualización (solución)

Gracias a la respuesta de Vineet Reynolds , esta versión funciona de acuerdo con mis expectativas. Muestra 3x INFO mensajes, y 3x mensajes FINE .

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)); } } }


Esta solución me parece mejor, con respecto a la facilidad de mantenimiento y el diseño para el cambio:

  1. Cree el archivo de propiedades de registro incrustándolo en la carpeta del proyecto de recursos, para incluirlo en el archivo jar:

    # Logging handlers = java.util.logging.ConsoleHandler .level = ALL # Console Logging java.util.logging.ConsoleHandler.level = ALL

  2. Cargue el archivo de propiedad desde el código:

    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) { // ... } }


Intenté otras variantes, esto puede ser apropiado

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


Los madereros solo registran el mensaje, es decir, crean los registros de registro (o solicitudes de registro). No publican los mensajes en los destinos, que son manejados por los Handlers. Establecer el nivel de un registrador, solo hace que cree registros que coincidan con ese nivel o más.

Puede que esté utilizando ConsoleHandler (no podría inferir dónde está su salida System.err o un archivo, pero supongo que es el primero), que de forma predeterminada establece registros de publicación del nivel Level.INFO . Deberá configurar este manejador para publicar registros de nivel Level.FINER y superiores para el resultado deseado.

Recomiendo leer la guía general de registro de Java , para comprender el diseño subyacente. La guía cubre la diferencia entre el concepto de un Logger y un Handler.

Editando el nivel del manejador

1. Usando el archivo de configuración

El archivo de propiedades java.util.logging (de forma predeterminada, este es el archivo logging.properties en JRE_HOME/lib ) se puede modificar para cambiar el nivel predeterminado de ConsoleHandler:

java.util.logging.ConsoleHandler.level = FINER

2. Crear controladores en tiempo de ejecución

Esto no se recomienda, ya que daría como resultado la anulación de la configuración global. Usar esto en su base de código dará como resultado una configuración de registrador posiblemente inmanejable.

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


¿Por qué mi registro Java no funciona?

proporciona un archivo jar que lo ayudará a averiguar por qué su inicio de sesión no funciona como se esperaba. Le proporciona un volcado completo de los registradores y manejadores que se han instalado y qué niveles se establecen y en qué nivel en la jerarquía de registro.


El porque

java.util.logging tiene un registrador de raíz que tiene como valor predeterminado Level.INFO , y un ConsoleHandler conectado a él que también se establece de manera predeterminada en Level.INFO . FINE es menor que INFO , por lo que los mensajes finos no se muestran de forma predeterminada.

Solución 1

Cree un registrador para toda su aplicación, por ejemplo, desde el nombre de su paquete o use Logger.getGlobal() y enganche su propio ConsoleLogger. Luego, solicite que el registrador de root se apague (para evitar la salida duplicada de mensajes de nivel superior) o solicite a su registrador que no reenvíe los registros a la raíz.

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

Solución 2

Alternativamente, puede bajar la barra del registrador raíz.

Puedes configurarlos por código:

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

O con el archivo de configuración de registro, si lo está usando :

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

Al disminuir el nivel global, puede comenzar a ver mensajes de las bibliotecas centrales, como desde algunos componentes Swing o JavaFX. En este caso, puede configurar un Filter en el registrador de raíz para filtrar los mensajes que no provengan de su programa.


POR QUÉ

Como lo menciona @Sheepy, la razón por la que no funciona es que java.util.logging.Logger tiene un registrador de raíz que tiene el valor predeterminado Level.INFO , y ConsoleHandler conectado a ese registrador de raíz también se establece de manera predeterminada en Level.INFO . Por lo tanto, para ver la salida FINE (, FINER o FINER ), debe establecer el valor predeterminado del registrador de raíz y su ConsoleHandler en Level.FINE siguiente manera:

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


El problema de su actualización (solución)

Como mencionó @mins, tendrá los mensajes impresos dos veces en la consola para INFO y superior: primero por el registrador anónimo, luego por su padre, el registrador de raíz que también tiene un ConsoleHandler configurado en INFO de forma predeterminada. Para deshabilitar el registrador de raíz, necesita agregar esta línea de código: logger.setUseParentHandlers(false);

Hay otras maneras de evitar que los registros se procesen de manera predeterminada. Controlador de la consola del registrador raíz mencionado por @Sheepy, por ejemplo:

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

Pero Logger.getLogger("").setLevel( Level.OFF ); no funcionará porque solo bloquea el mensaje que se pasa directamente al registrador de raíz, no el mensaje proviene de un registrador infantil. Para ilustrar cómo funciona la Logger Hierarchy , dibujo el siguiente diagrama:

public void setLevel(Level newLevel) establece el nivel de registro especificando qué niveles de mensajes serán registrados por este registrador. Los niveles de mensaje inferiores a este valor se descartarán. El valor de nivel Level.OFF se puede usar para desactivar el registro. Si el nuevo nivel es nulo, significa que este nodo debe heredar su nivel de su ancestro más cercano con un valor de nivel específico (no nulo).