Usar logs en Java (Parte 1)

En esta entrada mostraré como utilizar logs de Java para llevar un registro de los suceso importantes o de depuración de una aplicación Java. Con la finalidad de generar archivos de eventos para futuros diagnósticos de la aplicación.

El control de mensajes será incluido en nuestra aplicación como código duro y será definido por nosotros, lo que podemos dejar para ser administrado dinámicamente es a que nivel de detalle queremos reportar. Entonces yendo al punto, una forma común de incluir mensajes de log dentro de nuestra aplicación es de la siguiente forma:

import java.util.logging.Level;
import java.util.logging.Logger;
...
public void metodo() {
    try {
        ...
        Logger.getLogger(getClass().getName()).log(
            Level.INFO, "Mensaje informativo...");
        ...
    } catch (Exception err) {
        ...
        Logger.getLogger(getClass().getName()).log(
            Level.SEVERE, "Mensaje crítico...", err);
        ...
    }
}

Existen diferentes niveles (Level.[…]) para la cual desplegar un mensaje, los niveles son:

  • INFO: Mostrar mensajes informativos
  • CONFIG: Mostrar mensajes de configuración
  • WARNING: Mostrar mensajes de alerta
  • SEVERE: Mostrar mensajes críticos
  • FINE: Mostrar mensajes de depuración de nivel 1
  • FINER: Mostrar mensajes de depuración de nivel 2
  • FINEST: Mostrar mensajes de depuración de nivel 3

Para administrar el nivel de detalle de log que queremos reportar a consola o a un archivo, se utilizan los mismos niveles definidos anteriormente (INFO, CONFIG, etc.) y además también pueden utilizarse:

  • ALL: Muestra todos los mensajes
  • OFF: No muestra ningún mensaje

Una vez que la aplicación ya contiene las lineas de código para mostrar mensajes, podemos administrar la salida de estos mensajes, es decir, si queremos que vayan a un archivo, a pantalla ó a un socket, etc…, existen dos maneras de llevar acabo esta configuración: usando archivos de configuración o realizando la configuración desde el código de la aplicación, voy a mostrar las dos formas aunque prefiero realizar esta administración a través de archivos de configuración ya que permiten cambiar el nivel de log sin modificar el código fuente.



Usando archivos de configuración

Primero debemos especificar donde se encuentra nuestro archivo de configuración de log. También existen dos formas para indicar donde esta el archivo, la primera desde la ejecución de la aplicación con el parametro -Djava.util.logging.config.file:

java -Djava.util.logging.config.file=./log.properties 
    -cp ./classes:./lib/* ClassMain

Y la segunda desde código fuente:

public void metodo() {
    LogManager.getLogManager().readConfiguration(
        new FileInputStream("./log.properties"));
}

Un ejemplo de archivo de propiedades de log (“log.properties”) es:

# especificacion de detalle de log
# nivel de log global
.level = WARNING
# nivel de log unicamente para la clase pkg.subpkg.JobClass
pkg.subpkg.JobClass.level = INFO

# manejadores de salida de log
# se cargaron un manejador de archivos y
# manejador de consola
handlers = java.util.logging.FileHandler, 
    java.util.logging.ConsoleHandler

# configuración de manejador de archivos
# nivel soportado para archivos
java.util.logging.FileHandler.level = ALL
# archivo de almacenamiento de las salidas de log
java.util.logging.FileHandler.pattern = ./log/app%g.log
# maximo tamaño de archivo en bytes
java.util.logging.FileHandler.limit = 10485760
# maximo numero de archivos de logs
java.util.logging.FileHandler.count = 3
# clase para formatear salida hacia el archivo de log
java.util.logging.FileHandler.formatter = 
    java.util.logging.XMLFormatter
# anexar entrada al ultimo archivo (si es falso escribirá al
# inicio del archivo cuando la aplicación sea ejecutada)
java.util.logging.FileHandler.append = true

# configuración de manejador de consola
# nivel soportado para consola
java.util.logging.ConsoleHandler.level = SEVERE
# clase para formatear salida hacia consola
java.util.logging.ConsoleHandler.formatter = 
    java.util.logging.SimpleFormatter

Como consejo, a menudo el despliegue a consola es controlado por nosotros para reportar mensajes mas fáciles de entender al usuario, así que para eliminar los logs a consola utiliza java.util.logging.ConsoleHandler.level = OFF

Con esto podemos dar por terminado el uso de logs en Java.



Configuración de logs desde código fuente

Para tener un parámetro de referencia realizaré la misma configuración que se tiene utilizando el archivo de configuración, pero ahora desde código fuente.

import java.util.logging.*;
...
public void metodo()
        throws SecurityException, IOException {
    // creando manejador de archivo
    FileHandler fh = new FileHandler(
        "./log/app%g.log", //pattern
        10485760, //limit
        3, // count
        true); //append
    fh.setLevel(Level.ALL); // level
    fh.setFormatter(new XMLFormatter()); //formatter

    // agregar el manejador de archivo al log
    Logger.global.addHandler(fh);

    // el manejador de consola se agrega automaticamente, solo
    // cambiamos el nivel de detalle a desplegar
    Logger.global.getHandlers()[0].setLevel(Level.SEVERE);

    // se establece el nivel predeterminado global
    Logger.global.setLevel(Level.INFO);
}
...

Y bueno con esto terminamos la primera parte de uso de logs en Java, espero que les ayude en el desarrollo de sus proyectos personales o profesionales, saludos!!!
🙂

Ir a Usar logs en Java (parte 2)

Anuncios

16 pensamientos en “Usar logs en Java (Parte 1)

  1. Hola:

    ¿por qué utlizas el formato xml para el formato del log?
    Luego para leer el log, lo lees con algun programa? es que sino te sale un tocho muy grande e incomodo de leer.

    Gracias por el aporte, esta bien.

    • En realidad no me gustan ninguno de los formatos que Java maneja ni el de XML ni el de texto, si ves la segunda parte explico como crear un formato propio.

    • %g es el número de log, y también existe

      %t es el directorio temporal
      %h es el directorio del usuario
      %u es un número único como identificador

      • Mas preguntas Teacher:

        Quiero hacer que los logs de una clase no me los muestre. Entonces he puesto en el archivo de configuración:

        # nivel de log unicamente para la clase pkg.subpkg.JobClass
        pkg.subpkg.JobClass = INFO
        contenedor.Gestion = OFF

        Donde “Gestion” es la clase y “contenedor” el package, porque en las clases tengo escrito así:

        package contenedor;

        import java.io.File;

        Pero me sigue imprimiendo los logs de la clase 😦 guaa…

      • Una disculpa, se me fue un detalle al redactar el documento, para la personalización de log de una clase en especifico se tiene que colocar el atributo level, ejemplo:

        .level = INFO
        paquete.subpaquete.Clase1.level = OFF
        paquete.subpaquete.Clase2.level = FINEST

        Ya corregí el documento, gracias por la pregunta, si no nunca hubiera corregido el error.

  2. Buenas; estoy haciendo un proyecto que ordena un array de Objetos de tipo Dato (string nomb, int edad), mediante algoritmos de ordenación. Y necesito mostrar con trazas INFO y trazas FINE el proceso de lo que va ordenando.
    ¿¿Alguna idea o ayuda?? Muchas gracias

  3. I’m impressed, I must say. Rarely do I come across a blog that’s both equally educative and
    amusing, and let me tell you, you’ve hit the nail on the head. The issue is an issue that not enough folks are speaking intelligently about. Now i’m very
    happy I found this during my hunt for something relating to this.

  4. Hola, gracias por tu artículo, pero sólo comentarte una cosa que me ha vuelto loco: el log padre del que derivan todos los demás se llama “” (cadena vacía), y no Logger.global (además que ésta nomenclatura ya está deprecada).
    Si, por ejemplo, haces un
    Logger.global.getHandlers()[0].setLevel(Level.SEVERE);
    tal y como aparece en tu código, java te devuelve un error de null pointer, porque el logger llamado “global” no contiene nada. Ignoro para qué sirve el logger “global”, pero lo cierto es que como no le añadas propiedades, appenders y demás explícitamente, te aseguro que por defecto no contiene nada. En cambio el “” es el padre de todos y a partir de él se puede manejar el resto.
    Una última cosa, la forma segura de manejar los loggers de una aplicación sería un bucle del tipo:
    for(Handler handlerAux : Logger.getLogger(“”).getHandlers()){
    handlerAux.setLevel(Level.parse(strLevel));
    }
    En éste ejemplo se cambia el nivel de todos los loggers de una programa recorriéndose los hijos de “” (mucho mejor que asumir que la consola está en el elemento [0])

    Saludos.

  5. Hola que tal tengo una duda, con el codigo que proporcionas se obtiene el log en formato xml, como se puede hacer para obtener el log en formato de texto simple, ya que en la instruccion java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter la he cambiado por java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter y sigue mostrando la informacion del log en formato xml

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s